Commit 7de51eb9 authored by Nicolas Denoyelle's avatar Nicolas Denoyelle Committed by Swann Perarnau

[test] add area test for linux

parent 4c6b4490
...@@ -51,6 +51,12 @@ stamp-h1 ...@@ -51,6 +51,12 @@ stamp-h1
/missing /missing
/stamp-h1 /stamp-h1
version.h version.h
/m4/libtool.m4
/m4/ltmain.sh
/m4/ltoptions.m4
/m4/ltsugar.m4
/m4/ltversion.m4
/m4/lt~obsolete.m4
# autotest # autotest
tests/**/*.trs tests/**/*.trs
...@@ -65,3 +71,6 @@ tests/**/*.log ...@@ -65,3 +71,6 @@ tests/**/*.log
# editors # editors
*~ *~
# package config
aml.pc
...@@ -15,63 +15,89 @@ ...@@ -15,63 +15,89 @@
#include <numa.h> #include <numa.h>
#include <numaif.h> #include <numaif.h>
/* Bind memory on given nodeset with MPOL_BIND policy */ /* allowed binding flags */
#define AML_AREA_LINUX_BINDING_FLAG_BIND (MPOL_BIND) #define AML_AREA_LINUX_BINDING_FLAG_BIND (MPOL_BIND)
#define AML_AREA_LINUX_BINDING_FLAG_INTERLEAVE (MPOL_INTERLEAVE) #define AML_AREA_LINUX_BINDING_FLAG_INTERLEAVE (MPOL_INTERLEAVE)
#define AML_AREA_LINUX_BINDING_FLAG_PREFERRED (MPOL_PREFERRED) #define AML_AREA_LINUX_BINDING_FLAG_PREFERRED (MPOL_PREFERRED)
/* Flags ti pass */ /* allowed mmap flags to pass */
#define AML_AREA_LINUX_MMAP_FLAG_PRIVATE (MAP_PRIVATE) #define AML_AREA_LINUX_MMAP_FLAG_PRIVATE (MAP_PRIVATE | MAP_ANONYMOUS)
#define AML_AREA_LINUX_MMAP_FLAG_SHARED (MAP_SHARED) #define AML_AREA_LINUX_MMAP_FLAG_SHARED (MAP_SHARED | MAP_ANONYMOUS)
/* User data stored inside area */ /** User data stored inside area **/
struct aml_area_linux_data { struct aml_area_linux_data {
struct bitmask *nodeset; /* numanodes to use */ /** numanodes to use **/
int binding_flags; /* numaif.h mbind policy or AML_AREA_LINUX_FLAG_*/ struct bitmask *nodeset;
int mmap_flags; /* mmap flags */ /** numaif.h mbind policy or AML_AREA_LINUX_FLAG_* **/
int binding_flags;
/** mmap flags **/
int mmap_flags;
}; };
/** Initialize area data with struct aml_area_linux_binding **/ /**
* Initialize area data with struct aml_area_linux_binding. Subsequent calls to
* aml_area_mmap() with this returned area will apply binding settings.
* Returns NULL on failure with aml_errno set to:
* - AML_AREA_ENOMEM if there is not enough memory available for the operation
* - AML_AREA_EINVAL flags were not one of linux area flags.
* - AML_AREA_EDOM if binding nodeset is out of allowed nodeset.
**/
struct aml_area* aml_area_linux_create(const int mmap_flags, struct aml_area* aml_area_linux_create(const int mmap_flags,
const struct aml_bitmap *nodemask, const struct aml_bitmap *nodemask,
const int binding_flags); const int binding_flags);
/** Destroy area data containing struct aml_area_linux_binding **/ /**
* Destroy area data containing struct aml_area_linux_binding
**/
void void
aml_area_linux_destroy(struct aml_area* area); aml_area_linux_destroy(struct aml_area* area);
/** Bind memory to area data. Done in aml_area_linux_mmap() **/ /**
* Bind memory of size "size" pointed by "ptr" to binding set in "bind".
* If mbind call was not successfull, i.e AML_FAILURE is returned, then errno
* should be inspected for further error checking.
**/
int int
aml_area_linux_mbind(struct aml_area_linux_data *bind, aml_area_linux_mbind(struct aml_area_linux_data *bind,
void *ptr, void *ptr,
size_t size); size_t size);
/** Function to check whether binding of a ptr area match area settings. **/ /**
* Function to check whether binding of a ptr obtained with
* aml_area_linux_mmap() then aml_area_linux_mbind() match area settings.
* Returns 1 if mapped memory binding in ptr match area_data binding settings,
* else 0.
**/
int int
aml_area_linux_check_binding(struct aml_area_linux_data *area_data, aml_area_linux_check_binding(struct aml_area_linux_data *area_data,
void *ptr, void *ptr,
size_t size); size_t size);
/** Function call to aml_area_linux_mmap_generic() then bind the data. **/ /**
* mmap hook for aml area.
* Fails with AML_FAILURE. On failure errno should be checked for further
* error investigations.
**/
void* void*
aml_area_linux_mmap(const struct aml_area_data *area_data, aml_area_linux_mmap(const struct aml_area_data *area_data,
void *ptr, void *ptr,
size_t size); size_t size);
/** Building block function for unmapping memory **/ /**
* munmap hook for aml area, to unmap memory mapped with aml_area_linux_mmap().
* Fails with AML_FAILURE. On failure errno should be checked for further
* error investigations.
**/
int int
aml_area_linux_munmap(const struct aml_area_data* area_data, aml_area_linux_munmap(const struct aml_area_data *area_data,
void *ptr, void *ptr,
const size_t size); const size_t size);
/* linux area hooks */ /** linux area hooks. mmap hook will also bind data unlike header mmap hook. **/
extern struct aml_area_ops aml_area_linux_ops; extern struct aml_area_ops aml_area_linux_ops;
/* Default linux area with private mapping and no binding. */ /** Default linux area with private mapping and no binding. **/
extern const struct aml_area aml_area_linux; extern const struct aml_area aml_area_linux;
#endif //AML_AREA_LINUX_NUMA_H #endif //AML_AREA_LINUX_NUMA_H
...@@ -20,22 +20,29 @@ const char* aml_strerror(const int errno); ...@@ -20,22 +20,29 @@ const char* aml_strerror(const int errno);
**/ **/
void aml_perror(const char * msg); void aml_perror(const char * msg);
#define AML_SUCCESS 0 /* Generic value for success */ /* Generic value for success */
#define AML_FAILURE -1 /* Generic value for failure */ #define AML_SUCCESS 0
/* Generic value for failure */
#define AML_FAILURE -1
/************************************ /************************************
* Area error codes -2 .. -32 * Area error codes -2 .. -32
************************************/ ************************************/
#define AML_AREA_EINVAL -2 /* Invalid argument provided */ /* Invalid argument provided */
#define AML_AREA_ENOTSUP -3 /* Function not implemented for this type of area */ #define AML_AREA_EINVAL -2
#define AML_AREA_ENOMEM -4 /* Allocation failed */ /* Function not implemented for this type of area */
#define AML_AREA_EDOM -5 /* One arguent is out of allowed bounds */ #define AML_AREA_ENOTSUP -3
/* Allocation failed */
#define AML_AREA_ENOMEM -4
/* One arguent is out of allowed bounds */
#define AML_AREA_EDOM -5
/************************************ /************************************
* error bound * error bound
************************************/ ************************************/
#define AML_ERROR_MAX -6 /* Last error */ /* Last error */
#define AML_ERROR_MAX -7
#endif #endif
...@@ -16,12 +16,47 @@ ...@@ -16,12 +16,47 @@
#define AML_AREA_LINUX_MBIND_FLAGS MPOL_MF_MOVE #define AML_AREA_LINUX_MBIND_FLAGS MPOL_MF_MOVE
static int aml_area_linux_check_mmap_flags(const int mmap_flags){
switch(mmap_flags){
case AML_AREA_LINUX_MMAP_FLAG_PRIVATE:
break;
case AML_AREA_LINUX_MMAP_FLAG_SHARED:
break;
default:
return 0;
}
return 1;
}
static int aml_area_linux_check_binding_flags(const int binding_flags){
switch(binding_flags){
case AML_AREA_LINUX_BINDING_FLAG_BIND:
break;
case AML_AREA_LINUX_BINDING_FLAG_INTERLEAVE:
break;
case AML_AREA_LINUX_BINDING_FLAG_PREFERRED:
break;
default:
return 0;
}
return 1;
}
struct aml_area* aml_area_linux_create(const int mmap_flags, struct aml_area* aml_area_linux_create(const int mmap_flags,
const struct aml_bitmap *nodemask, const struct aml_bitmap *nodemask,
const int binding_flags) const int binding_flags)
{ {
struct aml_area_linux_data *d; struct aml_area_linux_data *d;
struct aml_area *area; struct aml_area *area;
/* Check flags */
if(!aml_area_linux_check_mmap_flags(mmap_flags) ||
!aml_area_linux_check_binding_flags(binding_flags)){
aml_errno = AML_AREA_EINVAL;
return NULL;
}
d = malloc(sizeof(*d)); d = malloc(sizeof(*d));
if(d == NULL){ if(d == NULL){
...@@ -29,27 +64,43 @@ struct aml_area* aml_area_linux_create(const int mmap_flags, ...@@ -29,27 +64,43 @@ struct aml_area* aml_area_linux_create(const int mmap_flags,
return NULL; return NULL;
} }
d->nodeset = numa_allocate_nodemask(); /* Check/set nodemask */
d->nodeset = numa_get_mems_allowed();
if(d->nodeset == NULL){ if(d->nodeset == NULL){
aml_errno = AML_AREA_ENOMEM; aml_errno = AML_AREA_ENOMEM;
goto err_with_data; goto err_with_data;
} }
if(nodemask != NULL){
int aml_last = aml_bitmap_last(nodemask);
int allowed_last = numa_bitmask_weight(d->nodeset);
while(!numa_bitmask_isbitset(d->nodeset, --allowed_last));
if(aml_last > allowed_last){
aml_errno = AML_AREA_EDOM;
goto err_with_nodeset;
}
aml_bitmap_copy_to_ulong(nodemask,
d->nodeset->maskp,
d->nodeset->size);
}
aml_bitmap_copy_to_ulong(nodemask, d->nodeset->maskp, d->nodeset->size); /* set area_data and area */
d->binding_flags = binding_flags; d->binding_flags = binding_flags;
d->mmap_flags = mmap_flags | MAP_ANONYMOUS; d->mmap_flags = mmap_flags;
area = malloc(sizeof(*area)); area = malloc(sizeof(*area));
if(area == NULL){ if(area == NULL){
aml_errno = AML_AREA_ENOMEM; aml_errno = AML_AREA_ENOMEM;
goto err_with_data; goto err_with_nodeset;
} }
area->data = (struct aml_area_data*)d; area->data = (struct aml_area_data*)d;
area->ops = &aml_area_linux_ops; area->ops = &aml_area_linux_ops;
return area; return area;
err_with_nodeset:
numa_free_nodemask(d->nodeset);
err_with_data: err_with_data:
free(d); free(d);
return NULL; return NULL;
...@@ -77,7 +128,7 @@ aml_area_linux_mbind(struct aml_area_linux_data *bind, ...@@ -77,7 +128,7 @@ aml_area_linux_mbind(struct aml_area_linux_data *bind,
if(bind->nodeset != NULL) if(bind->nodeset != NULL)
nodeset = bind->nodeset; nodeset = bind->nodeset;
else else
nodeset = numa_get_mems_allowed(); nodeset = numa_get_mems_allowed();
long err = mbind(ptr, long err = mbind(ptr,
size, size,
...@@ -88,19 +139,7 @@ aml_area_linux_mbind(struct aml_area_linux_data *bind, ...@@ -88,19 +139,7 @@ aml_area_linux_mbind(struct aml_area_linux_data *bind,
if(err == 0) if(err == 0)
return AML_SUCCESS; return AML_SUCCESS;
return AML_FAILURE;
switch(errno){
case EFAULT:
return AML_AREA_EDOM;
case EINVAL:
return AML_AREA_EINVAL;
case EIO:
return AML_AREA_EINVAL;
case ENOMEM:
return AML_AREA_ENOMEM;
case EPERM:
return AML_AREA_ENOTSUP;
}
} }
int int
...@@ -130,12 +169,17 @@ aml_area_linux_check_binding(struct aml_area_linux_data *area_data, ...@@ -130,12 +169,17 @@ aml_area_linux_check_binding(struct aml_area_linux_data *area_data,
if(mode != area_data->binding_flags) if(mode != area_data->binding_flags)
err = 0; err = 0;
for(i=0; i<numa_max_possible_node(); i++){ for(i=0; i<numa_max_possible_node(); i++){
if(numa_bitmask_isbitset(nodeset, i) != int ptr_set = numa_bitmask_isbitset(nodeset, i);
numa_bitmask_isbitset(area_data->nodeset, i)){ int bitmask_set = numa_bitmask_isbitset(area_data->nodeset, i);
err = 0; if(mode == AML_AREA_LINUX_BINDING_FLAG_BIND && ptr_set != bitmask_set)
break; goto binding_failed;
} if(mode == AML_AREA_LINUX_BINDING_FLAG_INTERLEAVE && ptr_set && !bitmask_set)
} goto binding_failed;
}
goto out;
binding_failed:
err = 0;
out: out:
numa_free_nodemask(nodeset); numa_free_nodemask(nodeset);
return err; return err;
...@@ -155,36 +199,10 @@ void* aml_area_linux_mmap(const struct aml_area_data *area_data, ...@@ -155,36 +199,10 @@ void* aml_area_linux_mmap(const struct aml_area_data *area_data,
if(out == MAP_FAILED){ if(out == MAP_FAILED){
out = NULL; out = NULL;
switch(errno){ aml_errno = AML_FAILURE;
case EAGAIN:
aml_errno = AML_AREA_ENOMEM;
break;
case EINVAL:
aml_errno = AML_AREA_EINVAL;
break;
case ENOMEM:
aml_errno = AML_AREA_ENOMEM;
break;
default:
aml_errno = AML_AREA_EINVAL;
break;
}
} }
if(out != NULL && (data->nodeset != NULL ||
data->binding_flags != MPOL_DEFAULT)){
int err = aml_area_linux_mbind(data, out, size);
if(err != AML_SUCCESS){
aml_errno = err;
goto binding_failed;
}
}
return out; return out;
binding_failed:
munmap(out, size);
return NULL;
} }
int int
...@@ -194,10 +212,35 @@ aml_area_linux_munmap(__attribute__ ((unused)) const struct aml_area_data* area_ ...@@ -194,10 +212,35 @@ aml_area_linux_munmap(__attribute__ ((unused)) const struct aml_area_data* area_
{ {
int err = munmap(ptr, size); int err = munmap(ptr, size);
if(err == -1) if(err == -1)
return AML_AREA_EINVAL; return AML_FAILURE;
return AML_SUCCESS; return AML_SUCCESS;
} }
static void*
aml_area_linux_mmap_mbind(const struct aml_area_data *area_data,
void *ptr,
size_t size)
{
void * out = aml_area_linux_mmap(area_data, ptr, size);
if(out == NULL)
return NULL;
struct aml_area_linux_data *data = (struct aml_area_linux_data *) area_data;
if(data->nodeset != NULL || data->binding_flags != MPOL_DEFAULT){
int err = aml_area_linux_mbind(data, out, size);
if(err != AML_SUCCESS){
aml_errno = err;
munmap(out, size);
return NULL;
}
}
return out;
}
/***************************************************************************** /*****************************************************************************
* Areas declaration * Areas declaration
*****************************************************************************/ *****************************************************************************/
...@@ -205,11 +248,11 @@ aml_area_linux_munmap(__attribute__ ((unused)) const struct aml_area_data* area_ ...@@ -205,11 +248,11 @@ aml_area_linux_munmap(__attribute__ ((unused)) const struct aml_area_data* area_
const struct aml_area_linux_data aml_area_linux_data_default = { const struct aml_area_linux_data aml_area_linux_data_default = {
.nodeset = NULL, .nodeset = NULL,
.binding_flags = MPOL_DEFAULT, .binding_flags = MPOL_DEFAULT,
.mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS .mmap_flags = AML_AREA_LINUX_MMAP_FLAG_PRIVATE
}; };
struct aml_area_ops aml_area_linux_ops = { struct aml_area_ops aml_area_linux_ops = {
.mmap = aml_area_linux_mmap, .mmap = aml_area_linux_mmap_mbind,
.munmap = aml_area_linux_munmap .munmap = aml_area_linux_munmap
}; };
......
...@@ -2,12 +2,18 @@ ...@@ -2,12 +2,18 @@
#include "aml/utils/error.h" #include "aml/utils/error.h"
static const char* aml_error_strings[-AML_ERROR_MAX] = { static const char* aml_error_strings[-AML_ERROR_MAX] = {
[AML_SUCCESS] = "aml success! If this is unexpected, check that this is called right after aml function returning an error.", [AML_SUCCESS] =
[-AML_FAILURE] = "aml function call failed (generic error).", "aml success! If this is unexpected, check that this is called right after aml function returning an error.",
[-AML_AREA_EINVAL] = "aml_area function called with invalid argument(s).", [-AML_FAILURE] =
[-AML_AREA_ENOTSUP] = "aml_area function is not implemented.", "aml function call failed (generic error).",
[-AML_AREA_ENOMEM] = "Not enough memory to fulfill aml_area function call.", [-AML_AREA_EINVAL] =
[-AML_AREA_EDOM] = "An argument is out possible bounds for this function call.", "aml_area function called with invalid argument(s).",
[-AML_AREA_ENOTSUP] =
"aml_area function is not implemented.",
[-AML_AREA_ENOMEM] =
"Not enough memory to fulfill aml_area function call.",
[-AML_AREA_EDOM] =
"An argument is out possible bounds for this function call.",
}; };
const char* const char*
......
...@@ -14,7 +14,8 @@ UTILS_TESTS = utils/test_vector \ ...@@ -14,7 +14,8 @@ UTILS_TESTS = utils/test_vector \
utils/test_version utils/test_version
AREA_TESTS = \ AREA_TESTS = \
area/test_area area/test_area \
area/test_linux
TILING_TESTS = tiling/test_tiling \ TILING_TESTS = tiling/test_tiling \
tiling/test_tiling_2d tiling/test_tiling_2d
...@@ -29,7 +30,7 @@ SCRATCH_TESTS = scratch/test_scratch_seq \ ...@@ -29,7 +30,7 @@ SCRATCH_TESTS = scratch/test_scratch_seq \
UNIT_TESTS = $(UTILS_TESTS) \ UNIT_TESTS = $(UTILS_TESTS) \
$(TILING_TESTS) \ $(TILING_TESTS) \
$(BINDING_TESTS) \ $(BINDING_TESTS) \
$(AREA_LINUX_TESTS) \ $(AREA_TESTS) \
$(DMA_LINUX_TESTS) \ $(DMA_LINUX_TESTS) \
$(SCRATCH_TESTS) $(SCRATCH_TESTS)
......
...@@ -10,11 +10,12 @@ ...@@ -10,11 +10,12 @@
#include "aml.h" #include "aml.h"
#include "aml/area/area.h" #include "aml/area/area.h"
#include "aml/area/linux.h" #include "aml/area/linux.h"
#include <assert.h>
void test_map(struct aml_area *area){ void test_map(const struct aml_area *area){
assert(area != NULL) assert(area != NULL);
assert(area->ops->map != NULL); assert(area->ops->mmap != NULL);
assert(area->ops->unmap != NULL); assert(area->ops->munmap != NULL);
void *ptr; void *ptr;
int err; int err;
...@@ -35,7 +36,7 @@ void test_aml_area(struct aml_area *area){ ...@@ -35,7 +36,7 @@ void test_aml_area(struct aml_area *area){
int main(int argc, char** argv){ int main(int argc, char** argv){
aml_init(&argc, &argv); aml_init(&argc, &argv);
test_aml_area(aml_area_linux); test_map(&aml_area_linux);
aml_finalize(); aml_finalize();
return 0; return 0;
} }
...@@ -7,72 +7,78 @@ ...@@ -7,72 +7,78 @@
* *
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
*******************************************************************************/ *******************************************************************************/
#include "aml.h" #include "aml.h"
#include "aml/area/area.h"
#include "aml/area/linux.h" #include "aml/area/linux.h"
#include <assert.h>
#include <string.h>
const size_t sizes[3] = {1, 1<<12, 1<<20};
const int binding_flags[3] = {
AML_AREA_LINUX_BINDING_FLAG_BIND,
AML_AREA_LINUX_BINDING_FLAG_INTERLEAVE,
AML_AREA_LINUX_BINDING_FLAG_PREFERRED
};
const int mmap_flags[2] = {
AML_AREA_LINUX_MMAP_FLAG_PRIVATE,
AML_AREA_LINUX_MMAP_FLAG_SHARED
};
void test_binding(struct aml_area *area){ void test_binding(struct aml_bitmap *bitmap){
void *ptr; void *ptr;
int err; int err;
size_t s; size_t s;
const size_t sizes[2] = {1, 1<<20}; int bf, mf, i, nnodes, binding_flag, mmap_flag;
struct aml_area *area;
for(s = 0; s<sizeof(sizes)/sizeof(*sizes); s++){
ptr = NULL;
err = area->ops->map(area, &ptr, sizes[s]); for(bf=0; bf<sizeof(binding_flags)/sizeof(*binding_flags); bf++){
if(err == AML_AREA_ENOMEM) binding_flag = binding_flags[bf];
continue; for(mf=0; mf<sizeof(mmap_flags)/sizeof(*mmap_flags); mf++){
if(err == AML_AREA_EINVAL) mmap_flag = mmap_flags[mf];
continue; for(s = 0; s<sizeof(sizes)/sizeof(*sizes); s++){
if(err == AML_SUCCESS){ area = aml_area_linux_create(mmap_flag, bitmap, binding_flag);
memset(ptr, 0, sizes[s]); assert(area != NULL);
if(area->ops->check_binding) ptr = area->ops->mmap((struct aml_area_data*)area->data,
assert(area->ops->check_binding(area, ptr, sizes[s]) > 0); NULL,
assert(area->ops->unmap(area, ptr, sizes[s]) == AML_SUCCESS); sizes[s]);
} else assert(ptr != NULL);
assert(0); memset(ptr, 0, sizes[s]);
assert(aml_area_linux_check_binding((struct aml_area_linux_data*)area->data, ptr, sizes[s]) > 0);
assert(area->ops->munmap((struct aml_area_data*)area->data, ptr, sizes[s]) == AML_SUCCESS);
}
}
} }
} }
void test_bind(struct aml_area *area){ void test_bind(){
if(area->ops->bind == NULL) struct bitmask *nodeset;
return; int i, num_nodes;
int err;
size_t i,j;
unsigned long flags = 1;
struct aml_bitmap bitmap; struct aml_bitmap bitmap;
err = area->ops->bind(area, NULL, 0);
if(err == AML_SUCCESS)
test_binding(area);
for(i = 0; i < sizeof(flags)*8 + 1; i++){ nodeset = numa_get_mems_allowed();
for(j = 0; j<AML_BITMAP_MAX; j++){ num_nodes = numa_bitmask_weight(nodeset);
aml_bitmap_zero(&bitmap);
aml_bitmap_set(&bitmap, j); aml_bitmap_fill(&bitmap);
err = area->ops->bind(area, &bitmap, flags); if(aml_bitmap_last(&bitmap) > num_nodes){
if(err == AML_SUCCESS) assert(aml_area_linux_create(AML_AREA_LINUX_MMAP_FLAG_PRIVATE,
test_binding(area); &bitmap,
} AML_AREA_LINUX_BINDING_FLAG_PREFERRED) == NULL);
flags = flags << 1; assert(aml_errno == AML_AREA_EDOM);
} }
}
void test_create(struct aml_area *area){ test_binding(NULL);
if(area->ops->create == NULL)
return;
assert(area->ops->destroy != NULL); aml_bitmap_zero(&bitmap);
for(i = 0; i<num_nodes; i++){
struct aml_area new; aml_bitmap_set(&bitmap, i);
int err; test_binding(&bitmap);
aml_bitmap_clear(&bitmap, i);
new.ops = area->ops; }
new.data = NULL;
assert(area->ops->create(&new) == AML_SUCCESS);
area->ops->destroy(&new);
} }
int main(int argc, char** argv){
test_bind();