Mentions légales du service

Skip to content
Snippets Groups Projects
descriptor.c 18.26 KiB
/**
 *
 * @copyright (c) 2009-2014 The University of Tennessee and The University
 *                          of Tennessee Research Foundation.
 *                          All rights reserved.
 * @copyright (c) 2012-2014 Inria. All rights reserved.
 * @copyright (c) 2012-2016 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria, Univ. Bordeaux. All rights reserved.
 *
 **/

/**
 *
 * @file descriptor.c
 *
 *  MORSE auxiliary routines
 *  MORSE is a software package provided by Univ. of Tennessee,
 *  Univ. of California Berkeley and Univ. of Colorado Denver
 *
 * @version 0.9.0
 * @author Mathieu Faverge
 * @author Cedric Castagnede
 * @date 2010-11-15
 *
 **/

/**
 *
 * @defgroup Descriptor
 * @brief Group descriptor routines exposed to users
 *
 */

#include <stdlib.h>
#include <assert.h>
#include "control/common.h"
#include "control/descriptor.h"
#include "runtime.h"

static int nbdesc = 0;

/*******************************************************************************
 *  Internal static descriptor initializer
 **/
MORSE_desc_t morse_desc_init(MORSE_enum dtyp, int mb, int nb, int bsiz,
                             int lm, int ln, int i, int j,
                             int m,  int n,  int p, int q)
{
  return morse_desc_init_user(dtyp, mb, nb, bsiz, lm, ln, i, j, m, n, p, q,
                              morse_getaddr_ccrb, morse_getblkldd_ccrb, morse_getrankof_2d);
}

/*******************************************************************************
 *  Internal static descriptor initializer for a block diagonal matrix
 **/
MORSE_desc_t morse_desc_init_diag(MORSE_enum dtyp, int mb, int nb, int bsiz,
                                  int lm, int ln, int i, int j,
                                  int m,  int n,  int p, int q)
{
  return morse_desc_init_user(dtyp, mb, nb, bsiz, lm, ln, i, j, m, n, p, q,
                              morse_getaddr_ccrb, morse_getblkldd_ccrb, morse_getrankof_2d_diag);
}

/*******************************************************************************
 *  Static descriptor initializer for users
 **/
MORSE_desc_t morse_desc_init_user(MORSE_enum dtyp, int mb, int nb, int bsiz,
                                  int lm, int ln, int i, int j,
                                  int m,  int n,  int p, int q,
                                  void* (*get_blkaddr)( const MORSE_desc_t*, int, int ),
                                  int (*get_blkldd)( const MORSE_desc_t*, int ),
                                  int (*get_rankof)( const MORSE_desc_t*, int, int ))
{
    MORSE_desc_t desc;
    desc.get_blkaddr = get_blkaddr;
    desc.get_blkldd  = get_blkldd;
    desc.get_rankof  = get_rankof;
    // Matrix properties
    desc.dtyp = dtyp;
    // seems useless
    desc.styp = MorseCCRB;
    desc.mb = mb;
    desc.nb = nb;
    desc.bsiz = bsiz;
    // Large matrix parameters
    desc.lm = lm;
    desc.ln = ln;
    // Large matrix derived parameters
    desc.lmt = (lm%mb==0) ? (lm/mb) : (lm/mb+1);
    desc.lnt = (ln%nb==0) ? (ln/nb) : (ln/nb+1);
    // Submatrix parameters
    desc.i = i;
    desc.j = j;
    desc.m = m;
    desc.n = n;
    // Submatrix derived parameters
    desc.mt = (m == 0) ? 0 : (i+m-1)/mb - i/mb + 1;
    desc.nt = (n == 0) ? 0 : (j+n-1)/nb - j/nb + 1;

    desc.id = nbdesc; nbdesc++;
    desc.occurences = 0;
    desc.use_mat = 1;
    desc.alloc_mat = 1;
    desc.register_mat = 1;

    RUNTIME_comm_rank( &(desc.myrank) );

    // Grid size
    desc.p = p;
    desc.q = q;

    // Local dimensions in tiles
    if ( desc.myrank < (p*q) ) {
        desc.llmt = (desc.lmt + p - 1) / p;
        desc.llnt = (desc.lnt + q - 1) / q;

        // Local dimensions
        if ( ((desc.lmt-1) % p) == (desc.myrank / q) ) {
            desc.llm  = ( desc.llmt - 1 ) * mb + ((lm%mb==0) ? mb : (lm%mb));
        } else {
            desc.llm  =  desc.llmt * mb;
        }

        if ( ((desc.lnt-1) % q) == (desc.myrank % q) ) {
            desc.lln  = ( desc.llnt - 1 ) * nb + ((ln%nb==0) ? nb : (ln%nb));
        } else {
            desc.lln  =  desc.llnt * nb;
        }

        desc.llm1 = (desc.llm/mb);
        desc.lln1 = (desc.lln/nb);
    } else {
      desc.llmt = 0;
      desc.llnt = 0;
      desc.llm  = 0;
      desc.lln  = 0;
      desc.llm1 = 0;
      desc.lln1 = 0;
    }

    // Matrix address
    desc.mat = NULL;
    desc.A21 = (size_t)(desc.llm - desc.llm%mb)*(size_t)(desc.lln - desc.lln%nb);
    desc.A12 = (size_t)(           desc.llm%mb)*(size_t)(desc.lln - desc.lln%nb) + desc.A21;
    desc.A22 = (size_t)(desc.llm - desc.llm%mb)*(size_t)(           desc.lln%nb) + desc.A12;

    RUNTIME_desc_init( &desc );

    return desc;
}

/*******************************************************************************
 *  Internal static descriptor initializer for submatrices
 **/
MORSE_desc_t* morse_desc_submatrix(MORSE_desc_t *descA, int i, int j, int m, int n )
{
    MORSE_desc_t *descB = malloc(sizeof(MORSE_desc_t));
    int mb, nb;

    if ( (descA->i + i + m) > descA->lm ) {
        morse_error("morse_desc_submatrix", "The number of rows (i+m) of the submatrix doesn't fit in the parent matrix");
        assert((descA->i + i + m) > descA->lm);
    }
    if ( (descA->j + j + n) > descA->ln ) {
        morse_error("morse_desc_submatrix", "The number of rows (j+n) of the submatrix doesn't fit in the parent matrix");
        assert((descA->j + j + n) > descA->ln);
    }

    memcpy( descB, descA, sizeof(MORSE_desc_t) );
    mb = descA->mb;
    nb = descA->nb;
    // Submatrix parameters
    descB->i = descA->i + i;
    descB->j = descA->j + j;
    descB->m = m;
    descB->n = n;
    // Submatrix derived parameters
    descB->mt = (m == 0) ? 0 : (descB->i+m-1)/mb - descB->i/mb + 1;
    descB->nt = (n == 0) ? 0 : (descB->j+n-1)/nb - descB->j/nb + 1;

    RUNTIME_desc_submatrix( descB );

    return descB;
}

/*******************************************************************************
 *  Check for descriptor correctness
 **/
int morse_desc_check(MORSE_desc_t *desc)
{
    if (desc == NULL) {
        morse_error("morse_desc_check", "NULL descriptor");
        return MORSE_ERR_NOT_INITIALIZED;
    }
    if (desc->mat == NULL && desc->use_mat == 1) {
        morse_error("morse_desc_check", "NULL matrix pointer");
        return MORSE_ERR_UNALLOCATED;
    }
    if (desc->dtyp != MorseRealFloat &&
        desc->dtyp != MorseRealDouble &&
        desc->dtyp != MorseComplexFloat &&
        desc->dtyp != MorseComplexDouble  ) {
        morse_error("morse_desc_check", "invalid matrix type");
        return MORSE_ERR_ILLEGAL_VALUE;
    }
    if (desc->mb <= 0 || desc->nb <= 0) {
        morse_error("morse_desc_check", "negative tile dimension");
        return MORSE_ERR_ILLEGAL_VALUE;
    }
    if (desc->bsiz < desc->mb*desc->nb) {
        morse_error("morse_desc_check", "tile memory size smaller than the product of dimensions");
        return MORSE_ERR_ILLEGAL_VALUE;
    }
    if (desc->lm <= 0 || desc->ln <= 0) {
        morse_error("morse_desc_check", "negative matrix dimension");
        return MORSE_ERR_ILLEGAL_VALUE;
    }
    if ((desc->lm < desc->m) || (desc->ln < desc->n)) {
        morse_error("morse_desc_check", "matrix dimensions larger than leading dimensions");
        return MORSE_ERR_ILLEGAL_VALUE;
    }
    if ((desc->i > 0 && desc->i >= desc->lm) || (desc->j > 0 && desc->j >= desc->ln)) {
        morse_error("morse_desc_check", "beginning of the matrix out of scope");
        return MORSE_ERR_ILLEGAL_VALUE;
    }
    if (desc->i+desc->m > desc->lm || desc->j+desc->n > desc->ln) {
        morse_error("morse_desc_check", "submatrix out of scope");
        return MORSE_ERR_ILLEGAL_VALUE;
    }
    return MORSE_SUCCESS;
}

/*******************************************************************************
 *
 **/
int morse_desc_mat_alloc( MORSE_desc_t *desc )
{

    size_t size = (size_t)(desc->llm) * (size_t)(desc->lln)
      * (size_t)MORSE_Element_Size(desc->dtyp);
    if ((desc->mat = RUNTIME_mat_alloc(size)) == NULL) {
        morse_error("morse_desc_mat_alloc", "malloc() failed");
        return MORSE_ERR_OUT_OF_RESOURCES;
    }

    RUNTIME_desc_create(desc);

    return MORSE_SUCCESS;
}

/*******************************************************************************
 *
 **/
int morse_desc_mat_free( MORSE_desc_t *desc )
{

    RUNTIME_desc_destroy( desc );

    if (desc->mat != NULL  &&
        desc->use_mat == 1 &&
        desc->alloc_mat == 1) {
        size_t size = (size_t)(desc->llm) * (size_t)(desc->lln)
            * (size_t)MORSE_Element_Size(desc->dtyp);

        RUNTIME_mat_free(desc->mat, size);
        desc->mat = NULL;
    }
    return MORSE_SUCCESS;
}

/** ***************************************************************************
 *
 * @ingroup Descriptor
 *
 *  MORSE_Desc_Create - Create matrix descriptor.
 *
 ******************************************************************************
 *
 * @param[out] desc
 *          On exit, descriptor of the matrix.
 *
 * @param[in] mat
 *          Memory location of the matrix. If mat is NULL, the space to store
 *          the data is automatically allocated by the call to the function.
 *
 * @param[in] dtyp
 *          Data type of the matrix:
 *          @arg MorseRealFloat:     single precision real (S),
 *          @arg MorseRealDouble:    double precision real (D),
 *          @arg MorseComplexFloat:  single precision complex (C),
 *          @arg MorseComplexDouble: double precision complex (Z).
 *
 * @param[in] mb
 *          Number of rows in a tile.
 *
 * @param[in] nb
 *          Number of columns in a tile.
 *
 * @param[in] bsiz
 *          Size in bytes including padding.
 *
 * @param[in] lm
 *          Number of rows of the entire matrix.
 *
 * @param[in] ln
 *          Number of columns of the entire matrix.
 *
 * @param[in] i
 *          Row index to the beginning of the submatrix.
 *
 * @param[in] j
 *          Column indes to the beginning of the submatrix.
 *
 * @param[in] m
 *          Number of rows of the submatrix.
 *
 * @param[in] n
 *          Number of columns of the submatrix.
 *
 * @param[in] p
 *          2D-block cyclic distribution in rows.
 *
 * @param[in] q
 *          2D-block cyclic distribution in columns.
 *
 ******************************************************************************
 *
 * @return
 *          \retval MORSE_SUCCESS successful exit
 *
 *****************************************************************************/
int MORSE_Desc_Create(MORSE_desc_t **desc, void *mat, MORSE_enum dtyp, int mb, int nb, int bsiz,
                      int lm, int ln, int i, int j, int m, int n, int p, int q)
{
    MORSE_context_t *morse;
    int status;

    morse = morse_context_self();
    if (morse == NULL) {
        morse_error("MORSE_Desc_Create", "MORSE not initialized");
        return MORSE_ERR_NOT_INITIALIZED;
    }
    /* Allocate memory and initialize the descriptor */
    *desc = (MORSE_desc_t*)malloc(sizeof(MORSE_desc_t));
    if (*desc == NULL) {
        morse_error("MORSE_Desc_Create", "malloc() failed");
        return MORSE_ERR_OUT_OF_RESOURCES;
    }
    **desc = morse_desc_init(dtyp, mb, nb, bsiz, lm, ln, i, j, m, n, p, q);

    if (mat == NULL) {

        size_t size = (size_t)((*desc)->llm) * (size_t)((*desc)->lln)
            * (size_t)MORSE_Element_Size((*desc)->dtyp);

        if (((*desc)->mat = RUNTIME_mat_alloc(size)) == NULL) {
            morse_error("MORSE_Desc_Create", "malloc() failed");
            return MORSE_ERR_OUT_OF_RESOURCES;
        }
        (*desc)->alloc_mat = 1;

    } else {
        (*desc)->mat = mat;
        /* memory of the matrix is handle by users */
        (*desc)->alloc_mat = 0;
    }

    /* Create scheduler structure like registering data */
    RUNTIME_desc_create( *desc );

    status = morse_desc_check(*desc);
    if (status != MORSE_SUCCESS) {
        morse_error("MORSE_Desc_Create", "invalid descriptor");
        return status;
    }

    return MORSE_SUCCESS;
}

/** ***************************************************************************
 *
 * @ingroup Descriptor
 *
 *  MORSE_Desc_Create_User - Create matrix descriptor for general applications.
 *
 ******************************************************************************
 *
 * @param[out] desc
 *          On exit, descriptor of the matrix.
 *
 * @param[in] mat
 *          Memory location of the matrix. If mat is NULL, the space to store
 *          the data is automatically allocated by the call to the function.
 *
 * @param[in] dtyp
 *          Data type of the matrix:
 *          @arg MorseRealFloat:     single precision real (S),
 *          @arg MorseRealDouble:    double precision real (D),
 *          @arg MorseComplexFloat:  single precision complex (C),
 *          @arg MorseComplexDouble: double precision complex (Z).
 *
 * @param[in] nb
 *          Number of rows and columns in a tile.
 *
 * @param[in] m
 *          Number of rows of the entire matrix.
 *
 * @param[in] n
 *          Number of columns of the entire matrix.
 *
  * @param[in] p
 *          2d-block cyclic partitioning, number of tiles in rows.
 *
 * @param[in] q
 *          2d-block cyclic partitioning, number of tiles in columns.
 *
 * @param[in] (*get_blkaddr)( const MORSE_desc_t *A, int m, int n)
 *          A function which return the address of the data corresponding to
 *          the tile A(m,n).
 *
 * @param[in] (*get_blkldd)( const MORSE_desc_t *A, int m)
 *          A function that return the leading dimension of the tile A(m,*).
 *
 * @param[in] (*get_rankof)( const MORSE_desc_t *A, int m, int n)
 *          A function that return the MPI rank of the tile A(m,n).
 *
 ******************************************************************************
 *
 * @return
 *          \retval MORSE_SUCCESS successful exit
 *
 *****************************************************************************/
int MORSE_Desc_Create_User(MORSE_desc_t **desc, void *mat, MORSE_enum dtyp, int mb, int nb, int bsiz,
                           int lm, int ln, int i, int j, int m, int n, int p, int q,
                           void* (*get_blkaddr)( const MORSE_desc_t*, int, int ),
                           int (*get_blkldd)( const MORSE_desc_t*, int ),
                           int (*get_rankof)( const MORSE_desc_t*, int, int ))
{
    MORSE_context_t *morse;
    int status;

    morse = morse_context_self();
    if (morse == NULL) {
        morse_error("MORSE_Desc_Create", "MORSE not initialized");
        return MORSE_ERR_NOT_INITIALIZED;
    }
    /* Allocate memory and initialize the descriptor */
    *desc = (MORSE_desc_t*)malloc(sizeof(MORSE_desc_t));
    if (*desc == NULL) {
        morse_error("MORSE_Desc_Create", "malloc() failed");
        return MORSE_ERR_OUT_OF_RESOURCES;
    }
    **desc = morse_desc_init_user(dtyp, mb, nb, bsiz, lm, ln, i, j, m, n, p, q,
        get_blkaddr, get_blkldd, get_rankof);


    /* if the user gives a pointer to the overall data (tiles) we can use it */
    (**desc).use_mat = (mat == NULL) ? 0 : 1;

    /* memory of the matrix is handle by users */
    (**desc).alloc_mat = 0;

    /* users data can have multiple forms: let him register tiles */
    (**desc).register_mat = 0;

    (**desc).mat = mat;

    /* Create scheduler structure like registering data */
    RUNTIME_desc_create( *desc );

    status = morse_desc_check(*desc);
    if (status != MORSE_SUCCESS) {
        morse_error("MORSE_Desc_Create", "invalid descriptor");
        return status;
    }

    return MORSE_SUCCESS;
}

/** ***************************************************************************
 *
 * @ingroup Descriptor
 *
 *  MORSE_Desc_Destroy - Destroys matrix descriptor.
 *
 ******************************************************************************
 *
 * @param[in] desc
 *          Matrix descriptor.
 *
 ******************************************************************************
 *
 * @return
 *          \retval MORSE_SUCCESS successful exit
 *
 *****************************************************************************/
int MORSE_Desc_Destroy(MORSE_desc_t **desc)
{
    MORSE_context_t *morse;

    morse = morse_context_self();
    if (morse == NULL) {
        morse_error("MORSE_Desc_Destroy", "MORSE not initialized");
        return MORSE_ERR_NOT_INITIALIZED;
    }

    if (*desc == NULL) {
        morse_error("MORSE_Desc_Destroy", "attempting to destroy a NULL descriptor");
        return MORSE_ERR_UNALLOCATED;
    }

    morse_desc_mat_free( *desc );
    free(*desc);
    *desc = NULL;
    return MORSE_SUCCESS;
}

/** ***************************************************************************
 *
 * @ingroup Descriptor
 *
 *  MORSE_Desc_Acquire - Ensures that all data of the descriptor are
 *  up-to-date.
 *
 ******************************************************************************
 *
 * @param[in] desc
 *          Matrix descriptor.
 *
 ******************************************************************************
 *
 * @return
 *          \retval MORSE_SUCCESS successful exit
 *
 *****************************************************************************/
int MORSE_Desc_Acquire (MORSE_desc_t  *desc) {
  return RUNTIME_desc_acquire( desc );
}

/** ***************************************************************************
 *
 * @ingroup Descriptor
 *
 *  MORSE_Desc_Release - Release the data of the descriptor acquired by the
 *  application. Should be called if MORSE_Desc_Acquire has been called on the
 *  descriptor and if you do not need to access to its data anymore.
 *
 ******************************************************************************
 *
 * @param[in] desc
 *          Matrix descriptor.
 *
 ******************************************************************************
 *
 * @return
 *          \retval MORSE_SUCCESS successful exit
 *
 *****************************************************************************/
int MORSE_Desc_Release (MORSE_desc_t  *desc) {
  return RUNTIME_desc_release( desc );
}

/** ***************************************************************************
 *
 * @ingroup Descriptor
 *
 *  MORSE_Desc_Getoncpu - Apply an acquire and a release on the data of the
 *  descriptors so that its values are up-to-date in the main memory.
 *
 ******************************************************************************
 *
 * @param[in] desc
 *          Matrix descriptor.
 *
 ******************************************************************************
 *
 * @return
 *          \retval MORSE_SUCCESS successful exit
 *
 *****************************************************************************/
int MORSE_Desc_Getoncpu(MORSE_desc_t  *desc) {
  return RUNTIME_desc_getoncpu( desc );
}