Commit 5c127cc9 authored by Swann Perarnau's avatar Swann Perarnau

Merge branch 'tests_layout' into 'staging'

generic tests in test_layout.c. It is now possible to test new layouts by providing a constructor.

See merge request !91
parents 01f8e4a2 70ebe483
Pipeline #8915 passed with stages
in 6 minutes and 27 seconds
......@@ -2,6 +2,13 @@ AM_COLOR_TESTS = yes
AM_CFLAGS = -I$(top_srcdir)/include $(PTHREAD_CFLAGS)
AM_LDFLAGS = ../src/libaml.la $(PTHREAD_LIBS)
if HAVE_CUDA
# LIBS is used instead of AM_LDFLAGS on purpose
# AM_LDFLAGS appends flags before libraries added before LDADD.
# Thus, when linking with libaml.la, linking with cuda is not done.
LIBS += $(CUDA_CFLAGS)
LIBS += $(CUDA_LIBS)
endif
if HAVE_CUDA
# LIBS is used instead of AM_LDFLAGS on purpose
......@@ -28,7 +35,22 @@ AREA_TESTS = \
area/test_area \
area/test_linux
LAYOUT_TESTS = layout/test_layout
noinst_LTLIBRARIES = liblayout_test.la
liblayout_test_la_CPPFLAGS =
liblayout_test_la_LDFLAGS =
liblayout_test_la_SOURCES = \
layout/coords.c \
layout/dense.c \
layout/layout.c \
layout/reshape.c
liblayout_test_la_LIBADD = ../src/libaml.la
LDADD = liblayout_test.la
LAYOUT_TESTS = \
layout/test_coords \
layout/test_dense \
layout/test_reshape \
layout/test_pad
TILING_TESTS = tiling/test_tiling
......@@ -38,7 +60,6 @@ DMA_LINUX_TESTS = dma/test_dma_linux_seq \
SCRATCH_TESTS = scratch/test_scratch_seq \
scratch/test_scratch_par
if HAVE_CUDA
AREA_TESTS += area/test_cuda
endif
......
......@@ -24,7 +24,7 @@ void test_device_mmap(const int device)
void *host_copy;
void *device_data;
struct aml_area *area;
int ns = sizeof(sizes) / sizeof(*sizes);
size_t ns = sizeof(sizes) / sizeof(*sizes);
int err;
size_t size;
......@@ -63,7 +63,7 @@ void test_host_mmap(const int device)
void *host_data;
void *host_copy;
struct aml_area *area;
int ns = sizeof(sizes) / sizeof(*sizes);
size_t ns = sizeof(sizes) / sizeof(*sizes);
size_t size;
assert(!aml_area_cuda_create(&area, device,
......@@ -91,7 +91,7 @@ void test_mapped_mmap(const int device)
void *host_copy;
void *device_data;
struct aml_area *area;
int ns = sizeof(sizes) / sizeof(*sizes);
size_t ns = sizeof(sizes) / sizeof(*sizes);
size_t size;
struct aml_area_cuda_mmap_options options = {.device = device,
.ptr = NULL, };
......@@ -167,7 +167,7 @@ void test_unified_mmap(const int device)
void *unified_data;
void *host_copy;
struct aml_area *area;
int ns = sizeof(sizes) / sizeof(*sizes);
size_t ns = sizeof(sizes) / sizeof(*sizes);
size_t size;
// Data initialization
......@@ -204,7 +204,7 @@ void test_unified_mmap(const int device)
int main(void)
{
int num_devices;
int flags;
unsigned int flags;
int has_device_map;
int has_unified_mem;
int has_register_ptr;
......
/*******************************************************************************
* 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
******************************************************************************/
/**
* This file contains utils function to set coordinates inside the elements
* of a layout.
**/
#include "aml.h"
#include <assert.h>
/** Count the number of bits required to store a value between 0 and n. **/
static size_t count_bits(size_t n)
{
size_t b = 0;
while (n > 0) {
n = n / 2;
b++;
};
return b;
}
void dims_nbits(const size_t ndims,
const size_t *dims,
size_t *bits)
{
for (size_t i = 0; i < ndims; i++)
bits[i] = count_bits(dims[i]);
}
uint64_t pack_coords(const size_t ndims,
const size_t *coords, const size_t *bits)
{
size_t nbit = 0;
uint64_t packed = 0;
// Start from last coord then shift left each new coord
for (size_t i = ndims - 1; i > 0; i--) {
nbit += bits[i];
assert(nbit <= 8 * sizeof(uint64_t));
packed = packed | coords[i]; // store coord into the bitmask
packed = packed << bits[i - 1]; // Shift for next coord
}
packed = packed | coords[0]; // store last coord into the bitmask
return packed;
}
void unpack_coords(uint64_t coords,
const size_t ndims, const size_t *bits, size_t *out)
{
size_t nbit = 0;
// Start from first coord then shift right to unpack next coords.
for (size_t i = 0; i < ndims; i++) {
nbit += bits[i];
assert(nbit <= 8 * sizeof(uint64_t));
// Fill a bitmask of bits[i] bits then use it to unpack the
// good bits.
out[i] = coords & ((1 << bits[i]) - 1);
// shift right to unpack next coords.
coords = coords >> bits[i];
}
}
void increment_coords(const size_t ndims,
const size_t *dims,
size_t *coords,
size_t n)
{
for (size_t c, j = ndims - 1; j < ndims && n > 0; j--) {
// Save the value of current coordinate.
c = coords[j];
// Update value in current coordinate.
coords[j] = (c + n) % dims[j];
// How much do we increment next coordinate.
n = (c + n) / dims[j];
}
}
/*******************************************************************************
* 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
******************************************************************************/
/**
* This file defines the functions to test on a supposedly dense layout.
**/
#include "test_layout.h"
/**
* Slice an hyperplan of a layout along one dimension.
* @param layout: the layout to slice.
* @param dim: the dimension out of hyperplan.
* @param hindex: The index in dim for selecting an hyperplan.
**/
static struct aml_layout *slice_hyperplan(struct aml_layout *layout,
size_t dim, size_t hindex)
{
struct aml_layout *slice;
size_t ndims = aml_layout_ndims(layout);
size_t dims[ndims];
size_t new_dims[ndims];
size_t offsets[ndims];
// Compute dimensions. They are the same except on hyperplan dim
// where it is 1.
assert(aml_layout_dims(layout, dims) == AML_SUCCESS);
for (size_t i = 0; i < ndims; i++)
new_dims[i] = dims[i];
new_dims[dim] = 1;
// On hyper plan dimension the slice is offseted by the hyperplan index
for (size_t i = 0; i < ndims; i++)
offsets[i] = 0;
offsets[dim] = hindex;
assert(!aml_layout_slice(layout, &slice, offsets, new_dims, NULL));
size_t dims_slice[ndims];
// Check slice dimensions are the same as the one requested.
assert(aml_layout_dims(slice, dims_slice) == AML_SUCCESS);
assert(!memcmp(new_dims, dims_slice, sizeof(dims_slice)));
return slice;
}
/**
* Test that all elements of an hyperplan have the same value as
* hyperplan index.
* @param layout: the layout to slice.
* @param dim: the dimension out of hyperplan.
* @param hindex: The index in dim of the hyperplan.
**/
static void test_slice_hyperplan(struct aml_layout *layout, size_t dim,
size_t hindex)
{
struct aml_layout *slice = slice_hyperplan(layout, dim, hindex);
assert(slice != NULL);
assert(aml_layout_order(layout) == aml_layout_order(slice));
size_t size = 1;
size_t ndims = aml_layout_ndims(layout);
size_t dims[ndims];
size_t dims_slice[ndims];
size_t coords[ndims];
size_t coords_slice[ndims];
size_t bits[ndims];
assert(aml_layout_dims(layout, dims) == AML_SUCCESS);
assert(aml_layout_dims(slice, dims_slice) == AML_SUCCESS);
dims_nbits(ndims, dims, bits);
for (size_t i = 0; i < ndims; i++) {
coords[i] = 0;
coords_slice[i] = 0;
size *= dims[i];
}
// For each element of the slice, check that coordinates stored
// inside value, match with the hyperplan coordinates.
for (size_t i = 0; i < size; i++) {
uint64_t *e = aml_layout_deref(slice, coords_slice);
unpack_coords(*e, ndims, bits, coords);
assert(coords[dim] == hindex);
increment_coords(ndims, dims_slice, coords_slice, 1);
}
free(slice);
}
void test_slice_dense(struct aml_layout *layout)
{
assert(aml_layout_fill_with_coords(layout) == AML_SUCCESS);
size_t ndims = aml_layout_ndims(layout);
size_t dims[ndims];
assert(aml_layout_dims(layout, dims) == AML_SUCCESS);
// Define the hyperplans case to check.
// We don't check all possible hyperplans to make it faster.
// We check first, middle and last dimensions as hyperplan dimensions.
// In each dimension, we check first, middle and last element of the
// dimension as hyperplan index.
size_t cases[9][2] = {
{0, 0}, {0, dims[0] / 2}, {0, dims[0] - 1},
{ndims / 2, 0}, {ndims / 2, dims[ndims / 2] / 2}, {ndims / 2,
dims[ndims /
2] - 1},
{ndims - 1, 0}, {ndims - 1, dims[ndims - 1] / 2}, {ndims - 1,
dims[ndims -
1] - 1}
};
for (size_t c = 0; c < 9; c++)
test_slice_hyperplan(layout, cases[c][0], cases[c][1]);
}
/*******************************************************************************
* 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
******************************************************************************/
/**
* This file contains helper functions on layouts.
**/
#include "test_layout.h"
#include "aml/layout/native.h"
int aml_layout_fill_with_coords(struct aml_layout *layout)
{
int err;
size_t ndims = aml_layout_ndims(layout);
size_t dims[ndims];
size_t coords[ndims];
size_t bits[ndims];
size_t nelems = 1;
assert(aml_layout_element_size(layout) >= 8);
err = aml_layout_dims(layout, dims);
if (err != AML_SUCCESS)
return err;
// count number of element.
for (size_t i = 0; i < ndims; i++) {
coords[i] = 0;
nelems *= dims[i];
}
// Packing coordinates space.
dims_nbits(ndims, dims, bits);
for (size_t i = 0; i < nelems; i++) {
// Get element
uint64_t *e = (uint64_t *) aml_layout_deref(layout, coords);
// Pack and store coordinates.
*e = pack_coords(ndims, coords, bits);
// Move to next coordinates.
increment_coords(ndims, dims, coords, 1);
}
return AML_SUCCESS;
}
int aml_layout_isequal(const struct aml_layout *a,
const struct aml_layout *b)
{
// Check order equality
if (aml_layout_order(a) != aml_layout_order(b))
return 0;
// Check number of dimensions equality
size_t ndims_a = aml_layout_ndims(a);
size_t ndims_b = aml_layout_ndims(b);
if (ndims_a != ndims_b)
return 0;
// Check dimensions equality
size_t dims_a[ndims_a];
size_t dims_b[ndims_b];
size_t nelem = 1;
assert(aml_layout_dims(a, dims_a) == AML_SUCCESS);
assert(aml_layout_dims(b, dims_b) == AML_SUCCESS);
for (size_t i = 0; i < ndims_a; i++) {
if (dims_a[i] != dims_b[i])
return 0;
nelem *= dims_a[i];
}
// Check elements equality
size_t coords[ndims_a];
for (size_t i = 0; i < ndims_a; i++)
coords[i] = 0;
for (size_t i = 0; i < nelem; i++) {
if (aml_layout_deref(a, coords) != aml_layout_deref(b, coords))
return 0;
increment_coords(ndims_a, dims_a, coords, 1);
}
return 1;
}
void test_layout_base(struct aml_layout *layout)
{
int order = aml_layout_order(layout);
assert(order == AML_LAYOUT_ORDER_COLUMN_MAJOR ||
order == AML_LAYOUT_ORDER_ROW_MAJOR);
size_t ndims = aml_layout_ndims(layout);
size_t dims[ndims];
size_t dims_native[ndims];
assert(aml_layout_dims_native(layout, dims_native) == AML_SUCCESS);
assert(aml_layout_dims(layout, dims) == AML_SUCCESS);
size_t element_size = aml_layout_element_size(layout);
assert(element_size != 0);
size_t n_elements = 1;
size_t coords[ndims];
size_t coords_native[ndims];
for (size_t i = 0; i < ndims; i++) {
n_elements *= dims[i];
coords[i] = 0;
coords_native[i] = 0;
}
// Try deref/deref_native on all elements
for (size_t i = 0; i < n_elements; i++) {
assert(aml_layout_deref_native(layout, coords_native) != NULL);
increment_coords(ndims, dims_native, coords_native, 1);
assert(aml_layout_deref(layout, coords) != NULL);
increment_coords(ndims, dims, coords, 1);
}
}
/*******************************************************************************
* 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
******************************************************************************/
/**
* This file defines the functions to test on a supposedly dense layout.
**/
#include "test_layout.h"
#include "aml/layout/reshape.h"
void test_layout_reshape(struct aml_layout *layout,
const size_t n_new_dims,
const size_t *new_dims)
{
struct aml_layout *b, *c;
assert(aml_layout_reshape(layout, &b, n_new_dims, new_dims) ==
AML_SUCCESS);
assert(aml_layout_order(b) == aml_layout_order(layout));
aml_layout_reshape_create(&c, layout, aml_layout_order(layout),
n_new_dims, new_dims);
assert(aml_layout_isequal(b, c));
free(b);
free(c);
}
/*******************************************************************************
* 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 "test_layout.h"
void test_pack_unpack_coords(const size_t ndims,
const size_t *dims,
const size_t *coords)
{
size_t unpacked[ndims];
size_t bits[ndims];
dims_nbits(ndims, dims, bits);
uint64_t packed = pack_coords(ndims, coords, bits);
unpack_coords(packed, ndims, bits, unpacked);
assert(!memcmp(coords, unpacked, sizeof(unpacked)));
}
void test_increment_coords(const size_t ndims, const size_t *dims)
{
size_t num = 1;
size_t coords[ndims];
size_t prev[ndims];
for (size_t i = 0; i < ndims; i++) {
num = num * dims[i];
coords[i] = 0;
prev[i] = 0;
}
for (size_t i = 0; i < num; i++) {
increment_coords(ndims, dims, coords, 1);
assert((coords[ndims - 1] == 0 &&
(prev[ndims - 1] == 0 ||
prev[ndims - 1] == dims[ndims - 1] - 1)) ||
coords[ndims - 1] == prev[ndims - 1] ||
coords[ndims - 1] == prev[ndims - 1] + 1);
prev[ndims - 1] = coords[ndims - 1];
for (size_t j = 0; j < ndims - 1; j++) {
assert((coords[j] == 0 &&
(prev[j] == 0 ||
prev[j] == dims[j] - 1)) ||
coords[j] == prev[j] ||
(coords[j] == prev[j] + 1 &&
coords[j + 1] == 0));
prev[j] = coords[j];
}
}
for (size_t i = 0; i < ndims; i++)
assert(coords[i] == 0);
}
int main(void)
{
size_t dims0[4] = { 5, 7, 2, 8 };
size_t coords0[4] = { 3, 2, 0, 6 };
test_increment_coords(4, dims0);
test_pack_unpack_coords(4, dims0, coords0);
return 0;
}
/*******************************************************************************
* 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 <assert.h>
#include "test_layout.h"
#include "aml/layout/dense.h"
void test_dense(void)
{
struct aml_layout *a, *b;
/* padd the dims to the closest multiple of 2 */
float memory[16][12][8][8][4];
size_t cpitch[5] = {
4,
4 * 4,
4 * 4 * 8,
4 * 4 * 8 * 8,
4 * 4 * 8 * 8 * 12
};
size_t dims[5] = { 2, 3, 7, 11, 13 };
size_t stride[5] = { 1, 2, 1, 1, 1 };
size_t dims_col[5] = { 2, 3, 7, 11, 13 };
size_t dims_row[5] = { 13, 11, 7, 3, 2 };
size_t pitch_col[5] = { 4, 8, 8, 12, 16 };
size_t pitch_row[5] = { 16, 12, 8, 8, 4 };
size_t stride_col[5] = { 1, 2, 1, 1, 1 };
size_t stride_row[5] = { 1, 1, 1, 2, 1 };
for (size_t i = 0; i < 4 * 8 * 8 * 12 * 16; i++)
((float *)(&memory[0][0][0][0][0]))[i] = (float)i;
/* test invalid input */
assert(aml_layout_dense_create(NULL, (void *)memory,
AML_LAYOUT_ORDER_COLUMN_MAJOR,
sizeof(int), 5, dims_col, stride_col,
pitch_col) == -AML_EINVAL);
assert(aml_layout_dense_create(&a, NULL,
AML_LAYOUT_ORDER_COLUMN_MAJOR,
sizeof(int), 5, dims_col, stride_col,
pitch_col) == -AML_EINVAL);
/* missing: we don't test the tags/order value */
assert(aml_layout_dense_create(&a, (void *)memory,
AML_LAYOUT_ORDER_COLUMN_MAJOR,
0, 5, dims_col, stride_col,
pitch_col) == -AML_EINVAL);
assert(aml_layout_dense_create(&a, (void *)memory,
AML_LAYOUT_ORDER_COLUMN_MAJOR,
sizeof(int), 0, dims_col, stride_col,
pitch_col) == -AML_EINVAL);
assert(aml_layout_dense_create(&a, (void *)memory,
AML_LAYOUT_ORDER_COLUMN_MAJOR,
sizeof(int), 5, NULL, stride_col,
pitch_col) == -AML_EINVAL);
aml_layout_dense_destroy(NULL);
/* test partial data */
assert(aml_layout_dense_create(&a,
(void *)memory,
AML_LAYOUT_ORDER_COLUMN_MAJOR,
sizeof(int),
5,
dims_col,
NULL, pitch_col) == AML_SUCCESS);
aml_layout_dense_destroy(&a);
assert(aml_layout_dense_create(&a,
(void *)memory,
AML_LAYOUT_ORDER_COLUMN_MAJOR,
sizeof(int),
5,
dims_col,
stride_col, NULL) == AML_SUCCESS);
aml_layout_dense_destroy(&a);
/* initialize column order layouts */
assert(aml_layout_dense_create(&a,
(void *)memory,
AML_LAYOUT_ORDER_COLUMN_MAJOR,
sizeof(int),
5,
dims_col,
stride_col, pitch_col) == AML_SUCCESS);
test_layout_base(a);
assert(aml_layout_dense_create(&b,
(void *)memory,
AML_LAYOUT_ORDER_COLUMN_MAJOR,
sizeof(int),
5,
dims_col,
stride_col, pitch_col) == AML_SUCCESS);
test_layout_base(b);
struct aml_layout_dense *adataptr;
struct aml_layout_dense *bdataptr;
adataptr = (struct aml_layout_dense *)a->data;
bdataptr = (struct aml_layout_dense *)b->data;
assert((intptr_t) (adataptr->stride) - (intptr_t) (adataptr->dims)
== 5 * sizeof(size_t));
/* some simple checks */
assert(!memcmp(adataptr->dims, dims, sizeof(size_t) * 5));
assert(!memcmp(adataptr->stride, stride, sizeof(size_t) * 5));
assert(!memcmp(adataptr->cpitch, cpitch, sizeof(size_t) * 5));
assert(!memcmp(bdataptr->dims, dims, sizeof(size_t) * 5));
/* test column major subroutines */
size_t dims_res[5];
size_t coords_test_col[5] = { 1, 2, 3, 4, 5 };
void *test_addr;
void *res_addr = (void *)&memory[5][4][3][2 * 2][1];
aml_layout_dims(a, dims_res);
assert(!memcmp(dims_res, dims_col, sizeof(size_t) * 5));
test_addr = aml_layout_deref(a, coords_test_col);
assert(res_addr == test_addr);
assert(aml_layout_order(a) == AML_LAYOUT_ORDER_COLUMN_MAJOR);
aml_layout_dense_destroy(&a);
/* test partial data */
assert(aml_layout_dense_create(&a,
(void *)memory,
AML_LAYOUT_ORDER_ROW_MAJOR,
sizeof(float),
5, dims_row,
NULL, pitch_row) == AML_SUCCESS);
aml_layout_dense_destroy(&a);
assert(aml_layout_dense_create(&a, (void *)memory,
AML_LAYOUT_ORDER_ROW_MAJOR,
sizeof(float),
5, dims_row,
stride_row, NULL) == AML_SUCCESS);
aml_layout_dense_destroy(&a);
/* initialize row order layouts */
assert(aml_layout_dense_create(&a, (void *)memory,
AML_LAYOUT_ORDER_ROW_MAJOR,
sizeof(float),
5, dims_row,
stride_row, pitch_row) == AML_SUCCESS);
adataptr = (struct aml_layout_dense *)a->data;
bdataptr = (struct aml_layout_dense *)b->data;
assert((intptr_t) (adataptr->stride) - (intptr_t) (adataptr->dims)
== 5 * sizeof(size_t));
/* some simple checks */
assert(!memcmp(adataptr->dims, dims, sizeof(size_t) * 5));
assert(!memcmp(adataptr->stride, stride, sizeof(size_t) * 5));
assert(!memcmp(bdataptr->dims, dims, sizeof(size_t) * 5));
assert(!memcmp(bdataptr->cpitch, cpitch, sizeof(size_t) * 5));
/* test row major subroutines */
size_t coords_test_row[5] = { 5, 4, 3, 2, 1 };
aml_layout_dims(a, dims_res);
assert(!memcmp(dims_res, dims_row, sizeof(size_t) * 5));
test_addr = aml_layout_deref(a, coords_test_row);