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

[feature] add generic copy operator for layouts

Add a function to create a layout from an existing one. We call it
duplicate to avoid the confusion with dma copies.

- ownership consistent with destroy operator: underlying layouts are
  also copied
- data is copied by the implementation, and the generic code takes care of
  the ops pointer.
parent e777c6bb
Pipeline #11005 passed with stages
in 3 minutes and 25 seconds
......@@ -452,6 +452,21 @@ struct aml_layout_ops {
int (*fprintf)(const struct aml_layout_data *data,
FILE *stream, const char *prefix);
/**
* Duplicate a layout (does not copy data, but deep copy
* metadata).
* If the layout relies on sublayouts (e.g. pad, reshape), those will be
* copied too.
* @param[in] layout a non-NULL handle to a layout to copy.
* @param[out] dest a pointer to where to store the new layout.
* @return -AML_ENOTSUP if operation is not available.
* @return -AML_ENOMEM if layout allocation failed.
* @return -AML_EINVAL if src or dest are NULL.
* @return AML_SUCCESS if copy succeeded.
**/
int (*duplicate)(const struct aml_layout *layout,
struct aml_layout **dest);
/**
* Destroys the layout and frees all associated memory.
**/
......@@ -622,6 +637,18 @@ int aml_layout_slice(const struct aml_layout *layout,
int aml_layout_fprintf(FILE *stream, const char *prefix,
const struct aml_layout *layout);
/**
* Creates a duplicate of the layout (independent deep copy of all its metadata,
* no user data is actually copied).
* @param[in] src the layout to duplicate
* @param[out] dest a pointer to where to store the new layout
* @return -AML_ENOMEM if layout allocation failed.
* @return -AML_EINVAL if src or dest are NULL.
* @return AML_SUCCESS if copy succeeded.
**/
int aml_layout_duplicate(const struct aml_layout *src,
struct aml_layout **dest);
/**
* Destroy (free) a layout, irrespective of its type.
* @param[in,out] layout the layout to destroy. NULL on return.
......
......@@ -159,5 +159,6 @@ struct aml_layout_ops aml_layout_cuda_ops = {
.slice = NULL,
.slice_native = NULL,
.fprintf = NULL,
.duplicate = NULL,
.destroy = NULL,
};
......@@ -128,6 +128,35 @@ int aml_layout_dense_create(struct aml_layout **layout,
return AML_SUCCESS;
}
int aml_layout_dense_duplicate(const struct aml_layout *layout,
struct aml_layout **dest)
{
const struct aml_layout_dense *data;
struct aml_layout_dense *dret;
struct aml_layout *ret;
int err;
data = (const struct aml_layout_dense *)layout->data;
if (layout->data == NULL || dest == NULL)
return -AML_EINVAL;
err = aml_layout_dense_alloc(&ret, data->ndims);
if (err)
return err;
ret->ops = layout->ops;
dret = (struct aml_layout_dense *)ret->data;
dret->ptr = data->ptr;
/* small optimization by copying the contents of the end part of our
* single allocation (everything after the _data struct).
*/
memcpy(dret->dims, data->dims, 3 * data->ndims * sizeof(size_t));
*dest = ret;
return AML_SUCCESS;
}
/*******************************************************************************
* COLUMN OPERATORS:
******************************************************************************/
......@@ -387,7 +416,7 @@ int aml_layout_column_fprintf(const struct aml_layout_data *data,
}
struct aml_layout_ops aml_layout_column_ops = {
aml_layout_column_deref,
.deref = aml_layout_column_deref,
aml_layout_column_deref,
aml_layout_dense_rawptr,
aml_layout_column_order,
......@@ -399,6 +428,7 @@ struct aml_layout_ops aml_layout_column_ops = {
aml_layout_column_slice,
aml_layout_column_slice,
aml_layout_column_fprintf,
aml_layout_dense_duplicate,
NULL,
};
......@@ -587,7 +617,7 @@ int aml_layout_row_fprintf(const struct aml_layout_data *data,
}
struct aml_layout_ops aml_layout_row_ops = {
aml_layout_row_deref,
.deref = aml_layout_row_deref,
aml_layout_column_deref,
aml_layout_dense_rawptr,
aml_layout_row_order,
......@@ -599,5 +629,6 @@ struct aml_layout_ops aml_layout_row_ops = {
aml_layout_row_slice,
aml_layout_row_slice_native,
aml_layout_row_fprintf,
aml_layout_dense_duplicate,
NULL,
};
......@@ -297,6 +297,17 @@ int aml_layout_fprintf(FILE *stream, const char *prefix,
return layout->ops->fprintf(layout->data, stream, p);
}
int aml_layout_duplicate(const struct aml_layout *layout,
struct aml_layout **dest)
{
assert(layout != NULL && layout->ops != NULL);
if (layout->ops->duplicate == NULL)
return -AML_ENOTSUP;
else
return layout->ops->duplicate(layout, dest);
}
void aml_layout_destroy(struct aml_layout **layout)
{
if (layout == NULL || *layout == NULL)
......
......@@ -106,6 +106,37 @@ int aml_layout_pad_create(struct aml_layout **layout, const int order,
return AML_SUCCESS;
}
int aml_layout_pad_duplicate(const struct aml_layout *layout,
struct aml_layout **dest)
{
const struct aml_layout_pad *data;
struct aml_layout_pad *dret;
struct aml_layout *ret;
size_t sz;
int err;
data = (const struct aml_layout_pad *)layout->data;
if (layout->data == NULL || dest == NULL)
return -AML_EINVAL;
err = aml_layout_pad_alloc(&ret, data->ndims, data->element_size);
if (err)
return err;
ret->ops = layout->ops;
dret = (struct aml_layout_pad *)ret->data;
aml_layout_duplicate(data->target, &dret->target);
dret->tags = data->tags;
/* small optimization to copy everything at the end of our single
* allocation, but careful about neutral and the arrays having a gap
**/
sz = ((char *)dret->neutral - (char *)dret->dims) + data->element_size;
memcpy(dret->dims, data->dims, sz);
*dest = ret;
return AML_SUCCESS;
}
void aml_layout_pad_destroy(struct aml_layout *l)
{
assert(l != NULL);
......@@ -211,6 +242,7 @@ struct aml_layout_ops aml_layout_pad_column_ops = {
NULL,
NULL,
aml_layout_pad_column_fprintf,
aml_layout_pad_duplicate,
aml_layout_pad_destroy,
};
......@@ -299,5 +331,6 @@ struct aml_layout_ops aml_layout_pad_row_ops = {
NULL,
NULL,
aml_layout_pad_row_fprintf,
aml_layout_pad_duplicate,
aml_layout_pad_destroy,
};
......@@ -125,6 +125,33 @@ int aml_layout_reshape_create(struct aml_layout **layout,
return AML_SUCCESS;
}
int aml_layout_reshape_duplicate(const struct aml_layout *layout,
struct aml_layout **dest)
{
const struct aml_layout_data_reshape *data;
struct aml_layout_data_reshape *dret;
struct aml_layout *ret;
int err;
data = (const struct aml_layout_data_reshape *)layout->data;
if (layout->data == NULL || dest == NULL)
return -AML_EINVAL;
err = aml_layout_reshape_alloc(&ret, data->ndims, data->target_ndims);
if (err)
return err;
ret->ops = layout->ops;
dret = (struct aml_layout_data_reshape *)ret->data;
aml_layout_duplicate(data->target, &dret->target);
/* small optimization, copying all data at the end of the structure */
memcpy(dret->dims, data->dims,
(2 * data->ndims + data->target_ndims) * sizeof(size_t));
*dest = ret;
return AML_SUCCESS;
}
void aml_layout_reshape_destroy(struct aml_layout *l)
{
assert(l != NULL);
......@@ -246,6 +273,7 @@ struct aml_layout_ops aml_layout_reshape_column_ops = {
NULL,
NULL,
aml_layout_reshape_column_fprintf,
aml_layout_reshape_duplicate,
aml_layout_reshape_destroy,
};
......@@ -337,5 +365,6 @@ struct aml_layout_ops aml_layout_reshape_row_ops = {
NULL,
NULL,
aml_layout_reshape_row_fprintf,
aml_layout_reshape_duplicate,
aml_layout_reshape_destroy,
};
......@@ -134,3 +134,10 @@ void test_layout_fprintf(FILE *stream, const char *prefix,
{
assert(!aml_layout_fprintf(stream, prefix, layout));
}
void test_layout_duplicate(struct aml_layout *layout)
{
struct aml_layout *l;
assert(!aml_layout_duplicate(layout, &l));
aml_layout_destroy(&l);
}
......@@ -198,7 +198,8 @@ void test_generics(void)
test_slice_dense(layout);
test_layout_reshape(layout, 2, new_dims_col);
test_layout_fprintf(stderr, "test-dense", layout);
free(layout);
test_layout_duplicate(layout);
aml_layout_destroy(&layout);
// Test slice and reshape layout row major.
assert(aml_layout_dense_create
......@@ -207,7 +208,7 @@ void test_generics(void)
test_slice_dense(layout);
test_layout_reshape(layout, 2, new_dims_row);
test_layout_fprintf(stderr, "test-dense", layout);
free(layout);
aml_layout_destroy(&layout);
}
int main(int argc, char *argv[])
......
......@@ -103,6 +103,10 @@ void test_layout_base(struct aml_layout *layout);
void test_layout_fprintf(FILE *stream, const char *prefix,
struct aml_layout *layout);
/**
* Duplicate for layouts. Check that we can copy the layout.
**/
void test_layout_duplicate(struct aml_layout *layout);
//------------------------------------------------------------------------------
// Testing a dense layout.
//------------------------------------------------------------------------------
......
......@@ -43,6 +43,7 @@ void test_pad(int (*layout_create) (struct aml_layout **layout,
ret_dims[1] = 12;
assert(*(float *)aml_layout_deref(b, ret_dims) == one);
test_layout_fprintf(stderr, "test-pad", b);
test_layout_duplicate(b);
aml_layout_destroy(&b);
}
......
......@@ -56,6 +56,7 @@ static void test_reshape_discontiguous(void)
AML_LAYOUT_ORDER_COLUMN_MAJOR,
5, new_dims_col);
test_layout_fprintf(stderr, "test-reshape", c);
test_layout_duplicate(c);
i = 0;
for (size_t j = 0; j < 3; j++)
for (size_t k = 0; k < 2; k++)
......@@ -91,6 +92,7 @@ static void test_reshape_discontiguous(void)
a,
AML_LAYOUT_ORDER_ROW_MAJOR, 5, new_dims_row);
test_layout_fprintf(stderr, "test-reshape", c);
test_layout_duplicate(c);
i = 0;
for (size_t j = 0; j < 3; j++)
for (size_t k = 0; k < 2; k++)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment