Commit 8ba4dd1a authored by Brice Videau's avatar Brice Videau

Added a thread single spinning thread engine for dma.

parent 09817b51
Pipeline #8431 failed with stages
in 13 seconds
...@@ -14,6 +14,7 @@ include_aml_layout_HEADERS = \ ...@@ -14,6 +14,7 @@ include_aml_layout_HEADERS = \
include_aml_dmadir=$(includedir)/aml/dma include_aml_dmadir=$(includedir)/aml/dma
include_aml_dma_HEADERS = \ include_aml_dma_HEADERS = \
aml/dma/linux-seq.h \ aml/dma/linux-seq.h \
aml/dma/linux-spin.h \
aml/dma/linux-par.h aml/dma/linux-par.h
include_aml_scratchdir=$(includedir)/aml/scratch include_aml_scratchdir=$(includedir)/aml/scratch
......
/*******************************************************************************
* 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_DMA_LINUX_SPIN_H
#define AML_DMA_LINUX_SPIN_H 1
/**
* @defgroup aml_dma_linux_spin "AML Parallel DMA"
* @brief Parallel DMA implementation.
*
* DMA logic implemented based on general linux API, asynchronous execution
* threads. This DMA implementation moves between pointers allocated with an
* aml_area_linux.
* @{
**/
/**
* Default table of dma request operations for linux
* parallel dma.
**/
extern struct aml_dma_ops aml_dma_linux_spin_ops;
/** Inside of a parallel request for linux movement. **/
struct aml_dma_request_linux_spin {
/**
* The type of dma request
* @see <aml.h>
**/
volatile int type;
/** The destination pointer of the data movement **/
struct aml_layout *dest;
/** The source pointer of the data movement **/
struct aml_layout *src;
/** The dma containing sequential operations **/
struct aml_dma_linux_spin *dma;
/** The actual thread in charge for the request progress**/
pthread_t thread;
pthread_spinlock_t lock;
/** operator for this request **/
aml_dma_operator op;
/** operator argument for this request **/
void *op_arg;
};
/** Inside of a parallel dma for linux movement. **/
struct aml_dma_linux_spin_data {
struct aml_dma_request_linux_spin req;
/** default operator for this dma **/
aml_dma_operator default_op;
/** default operator arg for this dma **/
void *default_op_arg;
};
/** Declaration of linux parallel dma operations **/
struct aml_dma_linux_spin_ops {
void *(*do_thread)(void *data);
};
/**
* aml_dma structure for linux based, parallel dma movement
* Needs to be initialized with aml_dma_linux_spin_create().
* Can be passed to generic aml_dma_*() functions.
**/
struct aml_dma_linux_spin {
struct aml_dma_linux_spin_ops ops;
struct aml_dma_linux_spin_data data;
};
/**
* Allocates and initializes a new parallel DMA.
*
* @param dma an address where the pointer to the newly allocated DMA structure
* will be stored.
* @param nbreqs the initial number of slots for asynchronous requests that are
* in-flight (will be increased automatically if necessary).
* @param nbthreads the number of threads to launch for each request.
* @param op: default operator
* @return 0 if successful; an error code otherwise.
**/
int aml_dma_linux_spin_create(struct aml_dma **dma,
aml_dma_operator op, void *op_arg);
/**
* Tears down a parallel DMA created with aml_dma_linux_spin_create.
* @param dma the address of a pointer to a parallel dma. Will be NULL after.
**/
void aml_dma_linux_spin_destroy(struct aml_dma **dma);
/**
* @}
**/
#endif // AML_LINUX_DMA_LINUX_SPIN_H
...@@ -19,6 +19,7 @@ LAYOUT_SOURCES = \ ...@@ -19,6 +19,7 @@ LAYOUT_SOURCES = \
DMA_SOURCES = \ DMA_SOURCES = \
dma/dma.c \ dma/dma.c \
dma/dma_linux_par.c \ dma/dma_linux_par.c \
dma/dma_linux_spin.c \
dma/dma_linux_seq.c dma/dma_linux_seq.c
TILING_SOURCES = \ TILING_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/dma/linux-spin.h"
#include "aml/layout/dense.h"
#include <assert.h>
#include <errno.h>
#include <sys/mman.h>
#define ASMPAUSE asm("" : : : "memory")
/*******************************************************************************
* Linux-backed, paruential dma
* The dma itself is organized into several different components
* - request types: copy
* - implementation of the request
* - user API (i.e. generic request creation and call)
* - how to init the dma
******************************************************************************/
/*******************************************************************************
* Requests:
******************************************************************************/
int aml_dma_request_linux_spin_copy_init(struct aml_dma_request_linux_spin *req,
struct aml_layout *dest,
struct aml_layout *src,
aml_dma_operator op, void *op_arg)
{
assert(req != NULL);
req->type = AML_DMA_REQUEST_TYPE_LAYOUT;
req->dest = dest;
req->src = src;
req->op = op;
req->op_arg = op_arg;
return 0;
}
int aml_dma_request_linux_spin_copy_destroy(struct aml_dma_request_linux_spin *r)
{
assert(r != NULL);
r->type = AML_DMA_REQUEST_TYPE_INVALID;
return 0;
}
/*******************************************************************************
* Internal functions
******************************************************************************/
void *aml_dma_linux_spin_do_thread(void *arg)
{
struct aml_dma_request_linux_spin *req =
(struct aml_dma_request_linux_spin *)arg;
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
while(1) {
pthread_spin_lock(&req->lock);
if (req->type != AML_DMA_REQUEST_TYPE_INVALID) {
req->op(req->dest, req->src, req->op_arg);
req->type = AML_DMA_REQUEST_TYPE_INVALID;
}
pthread_spin_unlock(&req->lock);
}
return NULL;
}
struct aml_dma_linux_spin_ops aml_dma_linux_spin_inner_ops = {
aml_dma_linux_spin_do_thread,
};
/*******************************************************************************
* Public API
******************************************************************************/
int aml_dma_linux_spin_create_request(struct aml_dma_data *d,
struct aml_dma_request **r,
struct aml_layout *dest,
struct aml_layout *src,
aml_dma_operator op, void *op_arg)
{
/* NULL checks done by the generic API */
assert(d != NULL);
assert(r != NULL);
assert(dest != NULL);
assert(src != NULL);
struct aml_dma_linux_spin *dma =
(struct aml_dma_linux_spin *)d;
struct aml_dma_request_linux_spin *req;
req = &(dma->data.req);
if (op == NULL)
op = dma->data.default_op;
if (op_arg == NULL)
op_arg = dma->data.default_op_arg;
pthread_spin_lock(&dma->data.req.lock);
if (req->type != AML_DMA_REQUEST_TYPE_INVALID) {
pthread_spin_unlock(&dma->data.req.lock);
return -AML_EINVAL;
}
aml_dma_request_linux_spin_copy_init(req, dest, src, op, op_arg);
pthread_spin_unlock(&dma->data.req.lock);
*r = (struct aml_dma_request *)req;
return 0;
}
int aml_dma_linux_spin_destroy_request(struct aml_dma_data *d,
struct aml_dma_request **r)
{
return 0;
}
int aml_dma_linux_spin_wait_request(struct aml_dma_data *d,
struct aml_dma_request **r)
{
assert(d != NULL);
assert(r != NULL);
struct aml_dma_linux_spin *dma = (struct aml_dma_linux_spin *)d;
struct aml_dma_request_linux_spin *req;
if (*r == NULL)
return -AML_EINVAL;
req = (struct aml_dma_request_linux_spin *)*r;
while (1) {
while (req->type != AML_DMA_REQUEST_TYPE_INVALID){ASMPAUSE;}
pthread_spin_lock(&(req->lock));//
if (req->type == AML_DMA_REQUEST_TYPE_INVALID) break;
pthread_spin_unlock(&(req->lock));
}
pthread_spin_unlock(&(req->lock));
*r = NULL;
return 0;
}
struct aml_dma_ops aml_dma_linux_spin_ops = {
aml_dma_linux_spin_create_request,
aml_dma_linux_spin_destroy_request,
aml_dma_linux_spin_wait_request,
};
/*******************************************************************************
* Init functions:
******************************************************************************/
int aml_dma_linux_spin_create(struct aml_dma **dma,
aml_dma_operator op, void *op_arg)
{
struct aml_dma *ret = NULL;
struct aml_dma_linux_spin *d;
if (dma == NULL)
return -AML_EINVAL;
*dma = NULL;
ret = AML_INNER_MALLOC_2(struct aml_dma, struct aml_dma_linux_spin);
if (ret == NULL)
return -AML_ENOMEM;
ret->data = AML_INNER_MALLOC_NEXTPTR(ret, struct aml_dma,
struct aml_dma_linux_spin);
ret->ops = &aml_dma_linux_spin_ops;
d = (struct aml_dma_linux_spin *)ret->data;
d->ops = aml_dma_linux_spin_inner_ops;
if (op == NULL) {
op = aml_copy_layout_generic;
op_arg = NULL;
}
d->data.default_op = op;
d->data.default_op_arg = op_arg;
/* allocate request array */
d->data.req.type = AML_DMA_REQUEST_TYPE_INVALID;
pthread_spin_init(&d->data.req.lock, PTHREAD_PROCESS_PRIVATE);
pthread_create(&d->data.req.thread, NULL, d->ops.do_thread, &d->data.req);
*dma = ret;
return 0;
}
void aml_dma_linux_spin_destroy(struct aml_dma **d)
{
struct aml_dma_linux_spin *dma;
if (d == NULL || *d == NULL)
return;
dma = (struct aml_dma_linux_spin *)(*d)->data;
struct aml_dma_request_linux_spin *req;
req = &dma->data.req;
if (req->type != AML_DMA_REQUEST_TYPE_INVALID) {
pthread_cancel(req->thread);
pthread_join(req->thread, NULL);
}
pthread_spin_destroy(&req->lock);
free(*d);
*d = NULL;
}
...@@ -23,6 +23,7 @@ LAYOUT_TESTS = layout/test_layout ...@@ -23,6 +23,7 @@ LAYOUT_TESTS = layout/test_layout
TILING_TESTS = tiling/test_tiling TILING_TESTS = tiling/test_tiling
DMA_LINUX_TESTS = dma/test_dma_linux_seq \ DMA_LINUX_TESTS = dma/test_dma_linux_seq \
dma/test_dma_linux_spin \
dma/test_dma_linux_par dma/test_dma_linux_par
if RUN_CUDA if RUN_CUDA
......
/*******************************************************************************
* 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/dense.h"
#include "aml/dma/linux-spin.h"
#include <assert.h>
int main(int argc, char *argv[])
{
struct aml_dma *dma;
size_t isz = 1<<16;
int idest[isz];
int isrc[isz];
struct aml_layout *idl, *isl;
/* library initialization */
aml_init(&argc, &argv);
/* support data structures */
assert(!aml_layout_dense_create(&idl, idest, 0, sizeof(int), 1, &isz,
NULL, NULL));
assert(!aml_layout_dense_create(&isl, isrc, 0, sizeof(int), 1, &isz,
NULL, NULL));
for (size_t i = 0; i < isz; i++) {
idest[i] = 42;
isrc[i] = 24;
}
/* invalid create input */
assert(aml_dma_linux_spin_create(NULL, NULL, NULL) == -AML_EINVAL);
/* invalid requests */
assert(!aml_dma_linux_spin_create(&dma, NULL, NULL));
assert(aml_dma_copy(dma, NULL, isl) == -AML_EINVAL);
assert(aml_dma_copy(dma, idl, NULL) == -AML_EINVAL);
struct aml_dma_request *r1, *r2;
/* force dma to increase its requests queue */
assert(!aml_dma_async_copy(dma, &r1, idl, isl));
assert(!aml_dma_wait(dma, &r1));
assert(!aml_dma_async_copy(dma, &r2, idl, isl));
assert(aml_dma_wait(dma, NULL) == -AML_EINVAL);
assert(!aml_dma_wait(dma, &r2));
assert(!memcmp(isrc, idest, isz*sizeof(int)));
aml_dma_linux_spin_destroy(&dma);
/* destroy a running dma */
assert(!aml_dma_linux_spin_create(&dma, NULL, NULL));
assert(!aml_dma_async_copy(dma, &r1, idl, isl));
aml_dma_linux_spin_destroy(&dma);
/* delete everything */
aml_layout_dense_destroy(&idl);
aml_layout_dense_destroy(&isl);
aml_finalize();
return 0;
}
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