Commit dfac0800 authored by Swann Perarnau's avatar Swann Perarnau

[feature] add padded tilings

Continue the work of merging the new tilings API, now with padded
tilings.
parent c11701cd
......@@ -24,6 +24,7 @@ include_aml_scratch_HEADERS = \
include_aml_tilingdir=$(includedir)/aml/tiling
include_aml_tiling_HEADERS = \
aml/tiling/native.h \
aml/tiling/pad.h \
aml/tiling/resize.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_TILING_PAD_H
#define AML_TILING_PAD_H 1
/**
* @defgroup aml_tiling_pad "AML Padded Tiling"
* @brief tiling with padding at the border
*
* Implementation of a tiling for which the border tiles are padded up to the
* requested size.
* @{
**/
/** Initialized structure containing operations for a tiling in column order.**/
extern struct aml_tiling_ops aml_tiling_pad_column_ops;
/** Initialized structure containing operations for a tiling in row order. **/
extern struct aml_tiling_ops aml_tiling_pad_row_ops;
struct aml_tiling_pad {
int tags;
const struct aml_layout *layout;
size_t ndims;
size_t *tile_dims;
size_t *dims;
size_t *border_tile_dims;
size_t *pad;
void *neutral;
};
int aml_tiling_pad_create(struct aml_tiling **t, int tags,
const struct aml_layout *l, size_t ndims,
const size_t *tile_dims, void *neutral);
void aml_tiling_pad_destroy(struct aml_tiling **t);
/**
* @}
**/
#endif /* AML_TILING_PAD_H */
......@@ -28,6 +28,7 @@ SCRATCH_SOURCES = \
TILING_SOURCES = \
tiling/tiling.c \
tiling/tiling_pad.c \
tiling/tiling_resize.c
UTILS_SOURCES = \
......
/*******************************************************************************
* 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/layout/native.h"
#include "aml/layout/pad.h"
#include "aml/tiling/pad.h"
/*******************************************************************************
* Create/Destroy
******************************************************************************/
static int aml_tiling_pad_alloc(struct aml_tiling **ret, size_t ndims,
size_t neutral_size)
{
struct aml_tiling *tiling;
struct aml_tiling_pad *data;
tiling = AML_INNER_MALLOC_EXTRA(struct aml_tiling,
struct aml_tiling_pad,
size_t, 4*ndims + neutral_size);
if (tiling == NULL) {
*ret = NULL;
return -AML_ENOMEM;
}
data = AML_INNER_MALLOC_NEXTPTR(tiling,
struct aml_tiling,
struct aml_tiling_pad);
tiling->data = (struct aml_tiling_data *)data;
data->tile_dims = AML_INNER_MALLOC_EXTRA_NEXTPTR(tiling,
struct aml_tiling,
struct aml_tiling_pad,
size_t, 0);
data->dims = AML_INNER_MALLOC_EXTRA_NEXTPTR(tiling,
struct aml_tiling,
struct aml_tiling_pad,
size_t, ndims);
data->border_tile_dims = AML_INNER_MALLOC_EXTRA_NEXTPTR(tiling,
struct aml_tiling,
struct aml_tiling_pad,
size_t, 2*ndims);
data->pad = AML_INNER_MALLOC_EXTRA_NEXTPTR(tiling,
struct aml_tiling,
struct aml_tiling_pad,
size_t, 3*ndims);
data->neutral = AML_INNER_MALLOC_EXTRA_NEXTPTR(tiling,
struct aml_tiling,
struct aml_tiling_pad,
size_t, 4*ndims);
data->layout = NULL;
data->ndims = ndims;
*ret = tiling;
return 0;
}
int aml_tiling_pad_create(struct aml_tiling **tiling,
const int tags,
const struct aml_layout *layout, size_t ndims,
const size_t *tile_dims, void *neutral)
{
struct aml_tiling *t;
struct aml_tiling_pad *data;
size_t element_size;
int err;
if (tiling == NULL || layout == NULL || tile_dims == NULL || !ndims
|| !neutral)
return -AML_EINVAL;
element_size = aml_layout_element_size(layout);
err = aml_tiling_pad_alloc(&t, ndims, element_size);
if (err)
return err;
data = (struct aml_tiling_pad *)t->data;
data->layout = layout;
switch (AML_TILING_ORDER(tags)) {
case AML_TILING_ORDER_ROW_MAJOR:
t->ops = &aml_tiling_pad_row_ops;
for (size_t i = 0; i < ndims; i++)
data->tile_dims[i] = tile_dims[ndims-i-1];
break;
case AML_TILING_ORDER_COLUMN_MAJOR:
t->ops = &aml_tiling_pad_column_ops;
for (size_t i = 0; i < ndims; i++)
data->tile_dims[i] = tile_dims[i];
break;
default:
free(t);
*tiling = NULL;
return -AML_EINVAL;
}
*tiling = t;
data->tags = tags;
size_t target_dims[ndims];
aml_layout_dims_native(layout, target_dims);
for (size_t i = 0; i < ndims; i++) {
data->border_tile_dims[i] = target_dims[i] % data->tile_dims[i];
data->dims[i] = target_dims[i] / data->tile_dims[i];
if (data->border_tile_dims[i] == 0)
data->border_tile_dims[i] = data->tile_dims[i];
else {
data->dims[i] += 1;
data->pad[i] = 1;
}
}
memcpy(data->neutral, neutral, element_size);
return 0;
}
void aml_tiling_pad_destroy(struct aml_tiling **tiling)
{
if (tiling == NULL)
return;
free(*tiling);
*tiling = NULL;
}
/*******************************************************************************
* Column Implementation
******************************************************************************/
struct aml_layout *
aml_tiling_pad_column_index(const struct aml_tiling_data *t,
const size_t *coords)
{
const struct aml_tiling_pad *d = (const struct aml_tiling_pad *)t;
struct aml_layout *ret;
assert(d != NULL);
size_t ndims = d->ndims;
size_t offsets[ndims];
size_t dims[ndims];
size_t strides[ndims];
for (size_t i = 0; i < ndims; i++)
assert(coords[i] < d->dims[i]);
for (size_t i = 0; i < ndims; i++) {
offsets[i] = coords[i] * d->tile_dims[i];
strides[i] = 1;
}
int pad = 0;
for (size_t i = 0; i < ndims; i++) {
if (coords[i] == d->dims[i] - 1) {
dims[i] = d->border_tile_dims[i];
if (d->pad[i])
pad = 1;
} else
dims[i] = d->tile_dims[i];
}
aml_layout_slice_native(d->layout, &ret, offsets, dims, strides);
if (pad) {
struct aml_layout *p_layout;
int order = aml_layout_order(d->layout);
if (AML_LAYOUT_ORDER(order) == AML_LAYOUT_ORDER_COLUMN_MAJOR) {
/* WARNING: OWNERSHIP!!! */
aml_layout_pad_create(&p_layout,
AML_LAYOUT_ORDER_COLUMN_MAJOR,
ret, d->tile_dims, d->neutral);
} else {
size_t row_dims[ndims];
for (size_t i = 0; i < ndims; i++)
row_dims[i] = d->tile_dims[i];
/* WARNING: OWNERSHIP!!! */
aml_layout_pad_create(&p_layout,
AML_LAYOUT_ORDER_ROW_MAJOR,
ret, row_dims, d->neutral);
}
return p_layout;
} else
return ret;
}
int aml_tiling_pad_column_tileid(const struct aml_tiling_data *t,
const size_t *coords)
{
const struct aml_tiling_pad *d = (const struct aml_tiling_pad *)t;
assert(d != NULL);
int ret = 0;
size_t ndims = d->ndims;
for (size_t i = 0; i < ndims; i++)
ret = (ret * d->dims[i]) + coords[i];
return ret;
}
int aml_tiling_pad_column_order(const struct aml_tiling_data *t)
{
(void)t;
return AML_TILING_ORDER_COLUMN_MAJOR;
}
int aml_tiling_pad_column_tile_dims(const struct aml_tiling_data *t,
size_t *tile_dims)
{
const struct aml_tiling_pad *d = (const struct aml_tiling_pad *)t;
assert(d != NULL);
memcpy((void *)tile_dims, (void *)d->tile_dims,
sizeof(size_t)*d->ndims);
return 0;
}
int aml_tiling_pad_column_dims(const struct aml_tiling_data *t,
size_t *dims)
{
const struct aml_tiling_pad *d = (const struct aml_tiling_pad *)t;
assert(d != NULL);
memcpy((void *)dims, (void *)d->dims, sizeof(size_t)*d->ndims);
return 0;
}
size_t aml_tiling_pad_column_ndims(const struct aml_tiling_data *t)
{
const struct aml_tiling_pad *d = (const struct aml_tiling_pad *)t;
assert(d != NULL);
return d->ndims;
}
size_t aml_tiling_pad_column_ntiles(const struct aml_tiling_data *t)
{
const struct aml_tiling_pad *d = (const struct aml_tiling_pad *)t;
assert(d != NULL);
size_t ret = 1;
for (size_t i = 0; i < d->ndims; i++)
ret = ret * d->dims[i];
return ret;
}
struct aml_tiling_ops aml_tiling_pad_column_ops = {
aml_tiling_pad_column_index,
aml_tiling_pad_column_index,
aml_tiling_pad_column_tileid,
aml_tiling_pad_column_order,
aml_tiling_pad_column_tile_dims,
aml_tiling_pad_column_dims,
aml_tiling_pad_column_dims,
aml_tiling_pad_column_ndims,
aml_tiling_pad_column_ntiles,
};
/*******************************************************************************
* Row Implementation
******************************************************************************/
struct aml_layout *
aml_tiling_pad_row_index(const struct aml_tiling_data *t, const size_t *coords)
{
const struct aml_tiling_pad *d = (const struct aml_tiling_pad *)t;
struct aml_layout *ret;
assert(d != NULL);
size_t ndims = d->ndims;
size_t offsets[ndims];
size_t dims[ndims];
size_t strides[ndims];
for (size_t i = 0; i < ndims; i++)
assert(coords[ndims - i - 1] < d->dims[i]);
for (size_t i = 0; i < ndims; i++) {
offsets[i] = coords[ndims - i - 1] * d->tile_dims[i];
strides[i] = 1;
}
int pad = 0;
for (size_t i = 0; i < ndims; i++) {
if (coords[ndims - i - 1] == d->dims[i] - 1) {
dims[i] = d->border_tile_dims[i];
if (d->pad[i])
pad = 1;
} else
dims[i] = d->tile_dims[i];
}
aml_layout_slice_native(d->layout, &ret, offsets, dims, strides);
if (pad) {
struct aml_layout *p_layout;
int order = aml_layout_order(d->layout);
if (AML_LAYOUT_ORDER(order) == AML_LAYOUT_ORDER_COLUMN_MAJOR) {
/* WARNING: OWNERSHIP!!! */
aml_layout_pad_create(&p_layout,
AML_LAYOUT_ORDER_COLUMN_MAJOR,
ret, d->tile_dims, d->neutral);
} else {
size_t row_dims[ndims];
for (size_t i = 0; i < ndims; i++)
row_dims[i] = d->tile_dims[ndims - i - 1];
/* WARNING: OWNERSHIP!!! */
aml_layout_pad_create(&p_layout,
AML_LAYOUT_ORDER_ROW_MAJOR,
ret, row_dims, d->neutral);
}
return p_layout;
} else
return ret;
}
int aml_tiling_pad_row_tileid(const struct aml_tiling_data *t,
const size_t *coords)
{
const struct aml_tiling_pad *d = (const struct aml_tiling_pad *)t;
assert(d != NULL);
int ret = 0;
size_t ndims = d->ndims;
for (size_t i = 0; i < ndims; i++)
ret = (ret * d->dims[i]) + coords[ndims - i - 1];
return ret;
}
int aml_tiling_pad_row_order(const struct aml_tiling_data *t)
{
(void)t;
return AML_TILING_ORDER_ROW_MAJOR;
}
int aml_tiling_pad_row_tile_dims(const struct aml_tiling_data *t,
size_t *tile_dims)
{
const struct aml_tiling_pad *d = (const struct aml_tiling_pad *)t;
assert(d != NULL);
for (size_t i = 0; i < d->ndims; i++)
tile_dims[i] = d->tile_dims[d->ndims - i - 1];
return 0;
}
int aml_tiling_pad_row_dims(const struct aml_tiling_data *t,
size_t *dims)
{
const struct aml_tiling_pad *d = (const struct aml_tiling_pad *)t;
assert(d != NULL);
for (size_t i = 0; i < d->ndims; i++)
dims[i] = d->dims[d->ndims - i - 1];
return 0;
}
size_t aml_tiling_pad_row_ndims(const struct aml_tiling_data *t)
{
const struct aml_tiling_pad *d = (const struct aml_tiling_pad *)t;
assert(d != NULL);
return d->ndims;
}
struct aml_tiling_ops aml_tiling_pad_row_ops = {
aml_tiling_pad_row_index,
aml_tiling_pad_column_index,
aml_tiling_pad_row_tileid,
aml_tiling_pad_row_order,
aml_tiling_pad_row_tile_dims,
aml_tiling_pad_row_dims,
aml_tiling_pad_column_dims,
aml_tiling_pad_row_ndims,
aml_tiling_pad_column_ntiles,
};
......@@ -12,6 +12,7 @@
#include "aml/layout/dense.h"
#include "aml/layout/native.h"
#include "aml/tiling/resize.h"
#include "aml/tiling/pad.h"
#include <assert.h>
void test_tiling_even_mixed(void)
......@@ -353,6 +354,267 @@ void test_tiling_uneven(void)
aml_tiling_resize_destroy(&tres);
}
void test_tiling_pad_even(void)
{
int memory[9][10][8];
int memoryres[9][10][8];
size_t dims_col[3] = {8, 10, 9};
size_t dims_row[3] = {9, 10, 8};
size_t stride[3] = {1, 1, 1};
size_t dims_tile_col[3] = {4, 10, 3};
size_t dims_tile_row[3] = {3, 10, 4};
size_t expected_dims_col[3] = {2, 1, 3};
size_t expected_dims_row[3] = {3, 1, 2};
int l = 0;
for (size_t i = 0; i < 9; i++)
for (size_t j = 0; j < 10; j++)
for (size_t k = 0; k < 8; k++, l++) {
memory[i][j][k] = l;
memoryres[i][j][k] = 0.0;
}
struct aml_layout *a, *ares;
aml_layout_dense_create(&a, memory,
AML_LAYOUT_ORDER_COLUMN_MAJOR,
sizeof(int), 3, dims_col, stride, dims_col);
aml_layout_dense_create(&ares, memoryres,
AML_LAYOUT_ORDER_COLUMN_MAJOR,
sizeof(int), 3, dims_col, stride, dims_col);
struct aml_tiling *t, *tres;
int neutral = 0xdeadbeef;
aml_tiling_pad_create(&t, AML_TILING_ORDER_COLUMN_MAJOR,
a, 3, dims_tile_col, &neutral);
aml_tiling_pad_create(&tres, AML_TILING_ORDER_COLUMN_MAJOR,
ares, 3, dims_tile_col, &neutral);
assert(aml_tiling_order(t) == AML_TILING_ORDER_COLUMN_MAJOR);
assert(aml_tiling_ndims(t) == 3);
size_t dims[3];
aml_tiling_tile_dims(t, dims);
assert(memcmp(dims, dims_tile_col, 3*sizeof(size_t)) == 0);
aml_tiling_dims(t, dims);
assert(memcmp(dims, expected_dims_col, 3*sizeof(size_t)) == 0);
for (size_t i = 0; i < expected_dims_col[2]; i++)
for (size_t j = 0; j < expected_dims_col[1]; j++)
for (size_t k = 0; k < expected_dims_col[0]; k++) {
struct aml_layout *b, *bres;
b = aml_tiling_index(t, (size_t[]){k, j, i});
bres = aml_tiling_index(tres,
(size_t[]){k, j, i});
aml_copy_layout_generic(bres, b, NULL);
free(b);
free(bres);
}
assert(memcmp(memory, memoryres, 8 * 10 * 9 * sizeof(int)) == 0);
aml_layout_dense_destroy(&a);
aml_layout_dense_destroy(&ares);
aml_tiling_pad_destroy(&t);
aml_tiling_pad_destroy(&tres);
aml_layout_dense_create(&a, memory,
AML_LAYOUT_ORDER_ROW_MAJOR,
sizeof(int), 3, dims_row, stride, dims_row);
aml_layout_dense_create(&ares, memoryres,
AML_LAYOUT_ORDER_ROW_MAJOR,
sizeof(int), 3, dims_row, stride, dims_row);
aml_tiling_pad_create(&t, AML_TILING_ORDER_ROW_MAJOR,
a, 3, dims_tile_row, &neutral);
aml_tiling_pad_create(&tres, AML_TILING_ORDER_ROW_MAJOR,
ares, 3, dims_tile_row, &neutral);
assert(aml_tiling_order(t) == AML_TILING_ORDER_ROW_MAJOR);
assert(aml_tiling_ndims(t) == 3);
aml_tiling_tile_dims(t, dims);
assert(memcmp(dims, dims_tile_row, 3*sizeof(size_t)) == 0);
aml_tiling_dims(t, dims);
assert(memcmp(dims, expected_dims_row, 3*sizeof(size_t)) == 0);
for (size_t i = 0; i < 9; i++)
for (size_t j = 0; j < 10; j++)
for (size_t k = 0; k < 8; k++, l++)
memoryres[i][j][k] = 0.0;
for (size_t i = 0; i < expected_dims_col[2]; i++)
for (size_t j = 0; j < expected_dims_col[1]; j++)
for (size_t k = 0; k < expected_dims_col[0]; k++) {
struct aml_layout *b, *bres;
b = aml_tiling_index(t, (size_t[]){i, j, k});
bres = aml_tiling_index(tres,
(size_t[]){i, j, k});
aml_copy_layout_generic(bres, b, NULL);
free(b);
free(bres);
}
assert(memcmp(memory, memoryres, 8 * 10 * 9 * sizeof(int)) == 0);
aml_layout_dense_destroy(&a);
aml_layout_dense_destroy(&ares);
aml_tiling_pad_destroy(&t);
aml_tiling_pad_destroy(&tres);
}
void test_tiling_pad_uneven(void)
{
int memory[8][10][7];
int memoryres[9][10][8];
size_t dims_col[3] = {7, 10, 8};
size_t dims_row[3] = {8, 10, 7};
size_t dims_col_res[3] = {8, 10, 9};
size_t dims_row_res[3] = {9, 10, 8};
size_t stride[3] = {1, 1, 1};
size_t dims_tile_col[3] = {4, 10, 3};
size_t dims_tile_row[3] = {3, 10, 4};
size_t expected_dims_col[3] = {2, 1, 3};
size_t expected_dims_row[3] = {3, 1, 2};
int l = 0;
for (size_t i = 0; i < 8; i++)
for (size_t j = 0; j < 10; j++)
for (size_t k = 0; k < 7; k++, l++)
memory[i][j][k] = l;
for (size_t i = 0; i < 9; i++)
for (size_t j = 0; j < 10; j++)
for (size_t k = 0; k < 8; k++, l++)
memoryres[i][j][k] = 0.0;
struct aml_layout *a, *ares;
aml_layout_dense_create(&a, memory,
AML_LAYOUT_ORDER_COLUMN_MAJOR,
sizeof(int), 3, dims_col, stride, dims_col);
aml_layout_dense_create(&ares, memoryres,
AML_LAYOUT_ORDER_COLUMN_MAJOR,
sizeof(int), 3, dims_col_res,
stride, dims_col_res);
struct aml_tiling *t, *tres;
int neutral = 0xdeadbeef;
aml_tiling_pad_create(&t, AML_TILING_ORDER_COLUMN_MAJOR,
a, 3, dims_tile_col, &neutral);
aml_tiling_pad_create(&tres, AML_TILING_ORDER_COLUMN_MAJOR,
ares, 3, dims_tile_col, &neutral);
assert(aml_tiling_order(t) == AML_TILING_ORDER_COLUMN_MAJOR);
assert(aml_tiling_ndims(t) == 3);
size_t dims[3];
aml_tiling_tile_dims(t, dims);
assert(memcmp(dims, dims_tile_col, 3*sizeof(size_t)) == 0);
aml_tiling_dims(t, dims);
assert(memcmp(dims, expected_dims_col, 3*sizeof(size_t)) == 0);
for (size_t i = 0; i < expected_dims_col[2]; i++)
for (size_t j = 0; j < expected_dims_col[1]; j++)
for (size_t k = 0; k < expected_dims_col[0]; k++) {
struct aml_layout *b, *bres;
b = aml_tiling_index(t, (size_t[]){k, j, i});
bres = aml_tiling_index(tres,
(size_t[]){k, j, i});
aml_copy_layout_generic(bres, b, NULL);
free(b);
free(bres);
}
for (size_t i = 0; i < 9; i++)
for (size_t j = 0; j < 10; j++)
for (size_t k = 0; k < 8; k++, l++)
if (k >= 7 || i >= 8)
assert(memoryres[i][j][k] ==
neutral);
else
assert(memoryres[i][j][k] ==
memory[i][j][k]);
aml_layout_dense_destroy(&a);
aml_layout_dense_destroy(&ares);
aml_tiling_pad_destroy(&t);
aml_tiling_pad_destroy(&tres);
aml_layout_dense_create(&a, memory,
AML_LAYOUT_ORDER_ROW_MAJOR,
sizeof(int), 3, dims_row, stride, dims_row);
aml_layout_dense_create(&ares, memoryres,
AML_LAYOUT_ORDER_ROW_MAJOR,
sizeof(int), 3, dims_row_res,
stride, dims_row_res);
aml_tiling_pad_create(&t, AML_TILING_ORDER_ROW_MAJOR,
a, 3, dims_tile_row, &neutral);
aml_tiling_pad_create(&tres, AML_TILING_ORDER_ROW_MAJOR,
ares, 3, dims_tile_row, &neutral);
assert(aml_tiling_order(t) == AML_TILING_ORDER_ROW_MAJOR);
assert(aml_tiling_ndims(t) == 3);
aml_tiling_tile_dims(t, dims);
assert(memcmp(dims, dims_tile_row, 3*sizeof(size_t)) == 0);
aml_tiling_dims(t, dims);
assert(memcmp(dims, expected_dims_row, 3*sizeof(size_t)) == 0);
for (size_t i = 0; i < 9; i++)
for (size_t j = 0; j < 10; j++)
for (size_t k = 0; k < 8; k++, l++)
memoryres[i][j][k] = 0.0;
for (size_t i = 0; i < expected_dims_col[2]; i++)
for (size_t j = 0; j < expected_dims_col[1]; j++)
for (size_t k = 0; k < expected_dims_col[0]; k++) {
struct aml_layout *b, *bres;
b = aml_tiling_index(t, (size_t[]){i, j, k});
bres = aml_tiling_index(tres,
(size_t[]){i, j, k});
aml_copy_layout_generic(bres, b, NULL);
free(b);