Mentions légales du service

Skip to content
Snippets Groups Projects
cham_tile_interface.c 24.87 KiB
/**
 *
 * @file starpu/cham_tile_interface.c
 *
 * @copyright 2012-2023 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria,
 *                      Univ. Bordeaux. All rights reserved.
 *
 ***
 *
 * @brief Chameleon tile interface for StarPU
 *
 * @version 1.2.0
 * @author Mathieu Faverge
 * @author Gwenole Lucas
 * @author Samuel Thibault
 * @date 2022-02-22
 *
 */
#include "chameleon_starpu.h"
#if defined(CHAMELEON_USE_HMAT)
#include "coreblas/hmat.h"

static inline void
cti_hmat_destroy( starpu_cham_tile_interface_t *cham_tile_interface )
{
    switch( cham_tile_interface->flttype ) {
    case ChamComplexDouble:
        hmat_zdestroy( cham_tile_interface->tile.mat );
        break;
    case ChamComplexFloat:
        hmat_cdestroy( cham_tile_interface->tile.mat );
        break;
    case ChamRealDouble:
        hmat_ddestroy( cham_tile_interface->tile.mat );
        break;
    case ChamRealFloat:
        hmat_sdestroy( cham_tile_interface->tile.mat );
        break;
    default:
        STARPU_ASSERT_MSG( 0, "cti_hmat_destroy(): unknown flttype\n" );
    }
    cham_tile_interface->tile.mat = NULL;
}

static inline size_t
cti_get_hmat_required_size( starpu_cham_tile_interface_t *cham_tile_interface )
{
    size_t size = 0;

    if ( (cham_tile_interface->tile.format & CHAMELEON_TILE_HMAT) &&
         (cham_tile_interface->tile.mat != NULL ) )
    {
        switch( cham_tile_interface->flttype ) {
        case ChamComplexDouble:
            size = hmat_zsize( cham_tile_interface->tile.mat );
            break;
        case ChamComplexFloat:
            size = hmat_csize( cham_tile_interface->tile.mat );
            break;
        case ChamRealDouble:
            size = hmat_dsize( cham_tile_interface->tile.mat );
            break;
        case ChamRealFloat:
            size = hmat_ssize( cham_tile_interface->tile.mat );
            break;
        default:
            STARPU_ASSERT_MSG( 0, "cti_get_hmat_required_size(cham_tile_interface): unknown flttype\n" );
        }
    }
    return size;
}
#else
static inline size_t
cti_get_hmat_required_size( starpu_cham_tile_interface_t *cham_tile_interface  __attribute__((unused)) ) {
    return 0;
}
#endif

static inline CHAM_tile_t *
cti_handle_get( starpu_data_handle_t handle )
{
    starpu_cham_tile_interface_t *cham_tile_interface = (starpu_cham_tile_interface_t *)
        starpu_data_get_interface_on_node( handle, STARPU_MAIN_RAM );

#ifdef STARPU_DEBUG
    STARPU_ASSERT_MSG( cham_tile_interface->id == STARPU_CHAM_TILE_INTERFACE_ID,
                       "Error. The given data is not a cham_tile." );
#endif

    return &(cham_tile_interface->tile);
}

int
cti_handle_get_m( starpu_data_handle_t handle )
{
    CHAM_tile_t *tile = cti_handle_get( handle );
    return tile->m;
}

int
cti_handle_get_n( starpu_data_handle_t handle )
{
    CHAM_tile_t *tile = cti_handle_get( handle );
    return tile->n;
}

static void
cti_init( void *data_interface )
{
    starpu_cham_tile_interface_t *cham_tile_interface = data_interface;
    cham_tile_interface->id = STARPU_CHAM_TILE_INTERFACE_ID;
    cham_tile_interface->allocsize = -1;
}

static void
cti_register_data_handle( starpu_data_handle_t  handle,
                          int                   home_node,
                          void                 *data_interface )
{
    starpu_cham_tile_interface_t *cham_tile_interface = (starpu_cham_tile_interface_t *) data_interface;
    int node;

    for (node = 0; node < STARPU_MAXNODES; node++)
    {
        starpu_cham_tile_interface_t *local_interface = (starpu_cham_tile_interface_t *)
            starpu_data_get_interface_on_node(handle, node);

        memcpy( local_interface, cham_tile_interface,
                sizeof( starpu_cham_tile_interface_t ) );

        if ( node != home_node )
        {
            local_interface->dev_handle = 0;
            local_interface->tile.mat  = NULL;
            local_interface->tile.ld   = -1;
        }
    }
}
static starpu_ssize_t
cti_allocate_data_on_node( void *data_interface, unsigned node )
{
    uintptr_t addr = 0, handle;
    starpu_cham_tile_interface_t *cham_tile_interface =
        (starpu_cham_tile_interface_t *) data_interface;

    uint32_t ld = cham_tile_interface->tile.m;
    starpu_ssize_t allocated_memory;

    allocated_memory = cham_tile_interface->allocsize;
    if ( allocated_memory <= 0 ) {
        return 0;
    }

    handle = starpu_malloc_on_node( node, allocated_memory );

    if ( !handle ) {
        return -ENOMEM;
    }

    if ( starpu_node_get_kind(node) != STARPU_OPENCL_RAM ) {
        addr = handle;
    }

    /* update the data properly */
    cham_tile_interface->tile.mat   = (void*)addr;
    cham_tile_interface->tile.ld    = ld;
    cham_tile_interface->dev_handle = handle;

    return allocated_memory;
}

static void
cti_free_data_on_node( void *data_interface, unsigned node )
{
    starpu_cham_tile_interface_t *cham_tile_interface =
        (starpu_cham_tile_interface_t *) data_interface;

#if defined(CHAMELEON_USE_HMAT)
    if ( (cham_tile_interface->tile.format & CHAMELEON_TILE_HMAT) &&
         (cham_tile_interface->tile.mat != NULL ) )
    {
        cti_hmat_destroy( cham_tile_interface );
    }
    else
#endif
    {
        assert( (uintptr_t)(cham_tile_interface->tile.mat) == cham_tile_interface->dev_handle );
    }

    starpu_free_on_node( node, cham_tile_interface->dev_handle, cham_tile_interface->allocsize );
    cham_tile_interface->tile.mat = NULL;
    cham_tile_interface->dev_handle = 0;
}

#if defined(HAVE_STARPU_REUSE_DATA_ON_NODE)
static void
cti_reuse_data_on_node( void *dst_data_interface, const void *cached_interface, unsigned node )
{
    (void)node;
    starpu_cham_tile_interface_t *dst_cham_tile =
        (starpu_cham_tile_interface_t *) dst_data_interface;
    starpu_cham_tile_interface_t *cached_cham_tile =
        (starpu_cham_tile_interface_t *) cached_interface;

    /* update the data properly */
    dst_cham_tile->tile.mat   = cached_cham_tile->tile.mat;
    dst_cham_tile->tile.ld    = dst_cham_tile->tile.m;
    dst_cham_tile->dev_handle = cached_cham_tile->dev_handle;
}
#endif

static void *
cti_to_pointer( void *data_interface, unsigned node )
{
    (void) node;
    starpu_cham_tile_interface_t *cham_tile_interface = data_interface;

    return (void*)(cham_tile_interface->tile.mat);
}

static size_t
cti_get_size(starpu_data_handle_t handle)
{
    starpu_cham_tile_interface_t *cham_tile_interface =
        starpu_data_get_interface_on_node( handle, STARPU_MAIN_RAM );
    size_t elemsize = CHAMELEON_Element_Size( cham_tile_interface->flttype );

#ifdef STARPU_DEBUG
    STARPU_ASSERT_MSG( cham_tile_interface->id == STARPU_CHAM_TILE_INTERFACE_ID,
                       "Error. The given data is not a cham_tile." );
#endif

    return cham_tile_interface->tile.m * cham_tile_interface->tile.n * elemsize;
}

static size_t
cti_get_alloc_size(starpu_data_handle_t handle)
{
    starpu_cham_tile_interface_t *cham_tile_interface =
        starpu_data_get_interface_on_node( handle, STARPU_MAIN_RAM );

#ifdef STARPU_DEBUG
    STARPU_ASSERT_MSG( cham_tile_interface->id == STARPU_CHAM_TILE_INTERFACE_ID,
                       "Error. The given data is not a cham_tile." );
#endif

    STARPU_ASSERT_MSG( cham_tile_interface->allocsize != (size_t)-1,
                       "The cham_tile allocation size needs to be defined" );

    return cham_tile_interface->allocsize;
}

static uint32_t
cti_footprint( starpu_data_handle_t handle )
{
    CHAM_tile_t *tile = cti_handle_get( handle );
    return starpu_hash_crc32c_be( tile->m, tile->n );
}

#if defined(HAVE_STARPU_REUSE_DATA_ON_NODE)
static uint32_t
cti_alloc_footprint( starpu_data_handle_t handle )
{
    return starpu_hash_crc32c_be( cti_handle_get_allocsize(handle), 0 );
}
#endif

static int
cti_compare( void *data_interface_a, void *data_interface_b )
{
    starpu_cham_tile_interface_t *cham_tile_a = (starpu_cham_tile_interface_t *) data_interface_a;
    starpu_cham_tile_interface_t *cham_tile_b = (starpu_cham_tile_interface_t *) data_interface_b;

    /* Two matrices are considered compatible if they have the same size */
    return ( cham_tile_a->tile.m  == cham_tile_b->tile.m  )
        && ( cham_tile_a->tile.n  == cham_tile_b->tile.n  )
        && ( cham_tile_a->flttype == cham_tile_b->flttype );
}

#if defined(HAVE_STARPU_REUSE_DATA_ON_NODE)
static int
cti_alloc_compare(void *data_interface_a, void *data_interface_b)
{
    starpu_cham_tile_interface_t *cham_tile_a = (starpu_cham_tile_interface_t *) data_interface_a;
    starpu_cham_tile_interface_t *cham_tile_b = (starpu_cham_tile_interface_t *) data_interface_b;

    /* Two matrices are considered compatible if they have the same allocated size */
    return ( cham_tile_a->allocsize == cham_tile_b->allocsize );
}
#endif

static void
cti_display( starpu_data_handle_t handle, FILE *f )
{
    starpu_cham_tile_interface_t *cham_tile_interface = (starpu_cham_tile_interface_t *)
        starpu_data_get_interface_on_node(handle, STARPU_MAIN_RAM);

#if defined(CHAMELEON_KERNELS_TRACE)
    fprintf( f, "%s{.m=%u,.n=%u}",
             cham_tile_interface->tile.name,
             cham_tile_interface->tile.m,
             cham_tile_interface->tile.n );
#else
    fprintf( f, "%u\t%u\t",
             cham_tile_interface->tile.m,
             cham_tile_interface->tile.n );
#endif
}

static int
cti_pack_data_fullrank( starpu_cham_tile_interface_t *cham_tile_interface,
                        void *ptr )
{
    char *matrix = (void *)cham_tile_interface->tile.mat;

    if ( cham_tile_interface->tile.m == cham_tile_interface->tile.ld ) {
        memcpy( ptr, matrix, cham_tile_interface->allocsize );
    }
    else {
        int   n;
        char *tmpptr = ptr;

        for(n=0; n<cham_tile_interface->tile.n; n++)
        {
            size_t elemsize = CHAMELEON_Element_Size( cham_tile_interface->flttype );
            size_t size = cham_tile_interface->tile.m * elemsize;
            memcpy( tmpptr, matrix, size );
            tmpptr += size;
            matrix += cham_tile_interface->tile.ld * elemsize;
        }
    }
    return 0;
}

static int
cti_pack_data_hmat( starpu_cham_tile_interface_t *cham_tile_interface,
                    void *ptr )
{
#if !defined(CHAMELEON_USE_HMAT)
    assert( 0 );
    (void)cham_tile_interface;
    (void)ptr;
#else
    hmat_matrix_t *mat = cham_tile_interface->tile.mat;
    STARPU_ASSERT_MSG( mat != NULL, "cti_pack_data_hmat: Try to pack a NULL pointer\n" );
    switch( cham_tile_interface->flttype ) {
    case ChamComplexDouble:
        hmat_zwrite( mat, ptr );
        break;
    case ChamComplexFloat:
        hmat_cwrite( mat, ptr );
        break;
    case ChamRealDouble:
        hmat_dwrite( mat, ptr );
        break;
    case ChamRealFloat:
        hmat_swrite( mat, ptr );
        break;
    default:
        STARPU_ASSERT_MSG( 0, "cti_pack_data_hmat: unknown flttype\n" );
    }
#endif
    return 0;
}

static int
cti_pack_data( starpu_data_handle_t handle, unsigned node, void **ptr, starpu_ssize_t *count )
{
    STARPU_ASSERT(starpu_data_test_if_allocated_on_node(handle, node));

    starpu_cham_tile_interface_t *cham_tile_interface = (starpu_cham_tile_interface_t *)
        starpu_data_get_interface_on_node(handle, node);
    size_t size;

    size   = (starpu_ssize_t)(cham_tile_interface->allocsize);
    size  += cti_get_hmat_required_size( cham_tile_interface );
    *count = size + sizeof(size_t) + sizeof(CHAM_tile_t);

    if ( ptr != NULL )
    {
        char *tmp;
        *ptr = (void *)starpu_malloc_on_node_flags( node, *count, 0 );
        tmp = (char*)(*ptr);

        /* Start by the size to allocate on reception */
        memcpy( tmp, &size, sizeof(size_t) );
        tmp += sizeof(size_t);

        /* Copy the tile metadata */
        memcpy( tmp, &(cham_tile_interface->tile), sizeof(CHAM_tile_t) );
        tmp += sizeof(CHAM_tile_t);

        /* Pack the real data */
        if ( cham_tile_interface->tile.format & CHAMELEON_TILE_FULLRANK ) {
            cti_pack_data_fullrank( cham_tile_interface, tmp );
        }
        else if ( cham_tile_interface->tile.format & CHAMELEON_TILE_HMAT ) {
            cti_pack_data_hmat( cham_tile_interface, tmp );
        }
        else {
            STARPU_ASSERT_MSG( 1, "Unsupported format for pack." );
        }
    }

    return 0;
}

static int
cti_unpack_data_fullrank( starpu_cham_tile_interface_t *cham_tile_interface,
                          void *ptr )
{
    char *matrix = (void *)cham_tile_interface->tile.mat;
    assert( cham_tile_interface->tile.format & CHAMELEON_TILE_FULLRANK );
    assert( matrix != NULL );

    if ( cham_tile_interface->tile.m == cham_tile_interface->tile.ld ) {
        memcpy( matrix, ptr, cham_tile_interface->allocsize );
    }
    else {
        int   n;
        char *tmpptr = ptr;

        for(n=0 ; n<cham_tile_interface->tile.n; n++)
        {
            size_t elemsize = CHAMELEON_Element_Size( cham_tile_interface->flttype );
            size_t size = cham_tile_interface->tile.m * elemsize;
            memcpy( matrix, tmpptr, size );
            tmpptr += size;
            matrix += cham_tile_interface->tile.ld * elemsize;
        }
    }
    return 0;
}

static int
cti_unpack_data_hmat( starpu_cham_tile_interface_t *cham_tile_interface,
                      void *ptr )
{
    assert( cham_tile_interface->tile.format & CHAMELEON_TILE_HMAT );
#if !defined(CHAMELEON_USE_HMAT)
    assert( 0 );
    (void)cham_tile_interface;
    (void)ptr;
#else
    hmat_matrix_t *mat = NULL;
    switch( cham_tile_interface->flttype ) {
    case ChamComplexDouble:
        mat = hmat_zread( ptr );
        break;
    case ChamComplexFloat:
        mat = hmat_cread( ptr );
        break;
    case ChamRealDouble:
        mat = hmat_dread( ptr );
        break;
    case ChamRealFloat:
        mat = hmat_sread( ptr );
        break;
    default:
        STARPU_ASSERT_MSG( 0, "cti_unpack_data_hmat: unknown flttype\n" );
    }
    cham_tile_interface->tile.mat = mat;
#endif
    return 0;
}

static int
cti_peek_data( starpu_data_handle_t handle, unsigned node, void *ptr, size_t count )
{
    STARPU_ASSERT(starpu_data_test_if_allocated_on_node(handle, node));

    starpu_cham_tile_interface_t *cham_tile_interface = (starpu_cham_tile_interface_t *)
        starpu_data_get_interface_on_node(handle, node);

    char *tmp = ptr;

#if defined(CHAMELEON_USE_MPI_DATATYPES)
    /*
     * We may end up here if an early reception occured before the handle of the
     * received data has been registered. Thus, datatype was not existant and we
     * need to unpack the data ourselves
     */
    STARPU_ASSERT( count == cham_tile_interface->allocsize );
    STARPU_ASSERT( cham_tile_interface->tile.format & CHAMELEON_TILE_FULLRANK );
#else
    {
        CHAM_tile_t dsttile;
        size_t size;

        /* Extract the size of the information to unpack */
        memcpy( &size, tmp, sizeof(size_t) );
        tmp += sizeof(size_t);

        /* Extract the tile metadata of the remote tile */
        memcpy( &dsttile, tmp, sizeof(CHAM_tile_t) );
        tmp += sizeof(CHAM_tile_t);

        assert( ( (dsttile.format & CHAMELEON_TILE_HMAT) && (cham_tile_interface->allocsize == 0   )) ||
                (!(dsttile.format & CHAMELEON_TILE_HMAT) && (cham_tile_interface->allocsize == size)) );

        /*
         * Update with the local information. Data is packed now, and do not
         * need leading dimension anymore
         */
        cham_tile_interface->tile.format = dsttile.format;
        cham_tile_interface->tile.ld = cham_tile_interface->tile.m;

        STARPU_ASSERT( cham_tile_interface->tile.m == dsttile.m );
        STARPU_ASSERT( cham_tile_interface->tile.n == dsttile.n );
        STARPU_ASSERT( count == cham_tile_interface->allocsize + sizeof(size_t) + sizeof(CHAM_tile_t) );
    }
#endif

    /* Unpack the real data */
    if ( cham_tile_interface->tile.format & CHAMELEON_TILE_FULLRANK ) {
        cti_unpack_data_fullrank( cham_tile_interface, tmp );
    }
    else if ( cham_tile_interface->tile.format & CHAMELEON_TILE_HMAT ) {
        cti_unpack_data_hmat( cham_tile_interface, tmp );
    }
    else {
        STARPU_ASSERT_MSG( 1, "Unsupported format for unpack." );
    }

    return 0;
}

static int
cti_unpack_data( starpu_data_handle_t handle, unsigned node, void *ptr, size_t count )
{
    cti_peek_data( handle, node, ptr, count );

    /* Free the received information */
    starpu_free_on_node_flags( node, (uintptr_t)ptr, count, 0 );

    return 0;
}

static starpu_ssize_t
cti_describe( void *data_interface, char *buf, size_t size )
{
    starpu_cham_tile_interface_t *cham_tile_interface = (starpu_cham_tile_interface_t *) data_interface;
#if defined(CHAMELEON_KERNELS_TRACE)
    return snprintf( buf, size, "M%ux%ux%u %s",
                     (unsigned) cham_tile_interface->tile.m,
                     (unsigned) cham_tile_interface->tile.n,
                     (unsigned) cham_tile_interface->flttype,
                     cham_tile_interface->tile.name);
#else
    return snprintf( buf, size, "M%ux%ux%u",
                     (unsigned) cham_tile_interface->tile.m,
                     (unsigned) cham_tile_interface->tile.n,
                     (unsigned) cham_tile_interface->flttype );
#endif
}

static int cti_copy_any_to_any( void *src_interface, unsigned src_node,
                                void *dst_interface, unsigned dst_node, void *async_data )
{
    starpu_cham_tile_interface_t *cham_tile_src = (starpu_cham_tile_interface_t *) src_interface;
    starpu_cham_tile_interface_t *cham_tile_dst = (starpu_cham_tile_interface_t *) dst_interface;
    size_t elemsize = CHAMELEON_Element_Size( cham_tile_src->flttype );
    size_t m        = (size_t)(cham_tile_src->tile.m);
    size_t n        = (size_t)(cham_tile_src->tile.n);
    size_t ld_src   = (size_t)(cham_tile_src->tile.ld);
    size_t ld_dst   = (size_t)(cham_tile_dst->tile.ld);
    int    ret      = 0;

    void *src_mat = CHAM_tile_get_ptr( &(cham_tile_src->tile) );
    void *dst_mat = CHAM_tile_get_ptr( &(cham_tile_dst->tile) );

    assert( ld_src >= m );
    assert( ld_dst >= m );

    assert( m == (size_t)(cham_tile_dst->tile.m) );
    assert( n == (size_t)(cham_tile_dst->tile.n) );

#if defined(CHAMELEON_KERNELS_TRACE)
    fprintf( stderr,
             "[ANY->ANY] src(%s, type:%s, m=%d, n=%d, ld=%d, ptr:%p) dest(%s, type:%s, m=%d, n=%d, ld=%d, ptr:%p)\n",
             cham_tile_src->tile.name, CHAM_tile_get_typestr( &(cham_tile_src->tile) ),
             cham_tile_src->tile.m, cham_tile_src->tile.n, cham_tile_src->tile.ld, src_mat,
             cham_tile_dst->tile.name, CHAM_tile_get_typestr( &(cham_tile_dst->tile) ),
             cham_tile_dst->tile.m, cham_tile_dst->tile.n, cham_tile_dst->tile.ld, dst_mat );
#endif

    m      = m      * elemsize;
    ld_src = ld_src * elemsize;
    ld_dst = ld_dst * elemsize;
#if defined(HAVE_STARPU_INTERFACE_COPY2D)
    if (starpu_interface_copy2d( (uintptr_t) src_mat, 0, src_node,
                                 (uintptr_t) dst_mat, 0, dst_node,
                                 m, n, ld_src, ld_dst, async_data ) ) {
        ret = -EAGAIN;
    }
#else
    if ( (ld_src == m) && (ld_dst == m) )
    {
        /* Optimize unpartitioned and y-partitioned cases */
        if ( starpu_interface_copy( (uintptr_t) src_mat, 0, src_node,
                                    (uintptr_t) dst_mat, 0, dst_node,
                                    m * n, async_data ) )
        {
            ret = -EAGAIN;
	}
    }
    else
    {
        unsigned y;
        for (y = 0; y < n; y++)
        {
            uint32_t src_offset = y * ld_src;
            uint32_t dst_offset = y * ld_dst;

            if ( starpu_interface_copy( (uintptr_t) src_mat, src_offset, src_node,
                                        (uintptr_t) dst_mat, dst_offset, dst_node,
                                        m, async_data ) )
            {
                ret = -EAGAIN;
            }
        }
    }
#endif

    starpu_interface_data_copy( src_node, dst_node, m * n );

    return ret;
}

static const struct starpu_data_copy_methods cti_copy_methods =
{
    .any_to_any = cti_copy_any_to_any,
};

struct starpu_data_interface_ops starpu_interface_cham_tile_ops =
{
    .init                  = cti_init,
    .register_data_handle  = cti_register_data_handle,
    .allocate_data_on_node = cti_allocate_data_on_node,
    .free_data_on_node     = cti_free_data_on_node,
#if defined(HAVE_STARPU_REUSE_DATA_ON_NODE)
    .reuse_data_on_node    = cti_reuse_data_on_node,
    .alloc_compare         = cti_alloc_compare,
    .alloc_footprint       = cti_alloc_footprint,
#endif
    .to_pointer            = cti_to_pointer,
    .get_size              = cti_get_size,
    .get_alloc_size        = cti_get_alloc_size,
    .footprint             = cti_footprint,
    .compare               = cti_compare,
    .display               = cti_display,
    .pack_data             = cti_pack_data,
#if defined(HAVE_STARPU_DATA_PEEK)
    .peek_data             = cti_peek_data,
#endif
    .unpack_data           = cti_unpack_data,
    .describe              = cti_describe,
    .copy_methods          =&cti_copy_methods,
    .interfaceid           = STARPU_UNKNOWN_INTERFACE_ID,
    .interface_size        = sizeof(starpu_cham_tile_interface_t),
    .name                  = "STARPU_CHAM_TILE_INTERFACE"
};

void
starpu_cham_tile_register( starpu_data_handle_t *handleptr,
                           int                   home_node,
                           CHAM_tile_t          *tile,
                           cham_flttype_t        flttype )
{
    size_t elemsize = CHAMELEON_Element_Size( flttype );
    starpu_cham_tile_interface_t cham_tile_interface =
        {
            .id         = STARPU_CHAM_TILE_INTERFACE_ID,
            .flttype    = flttype,
            .dev_handle = (intptr_t)(tile->mat),
            .allocsize  = -1,
            .tilesize   = tile->m * tile->n * elemsize,
        };
    memcpy( &(cham_tile_interface.tile), tile, sizeof( CHAM_tile_t ) );

    if ( tile->format & CHAMELEON_TILE_FULLRANK ) {
        cham_tile_interface.allocsize = tile->m * tile->n * elemsize;
    }
    else if ( tile->format & CHAMELEON_TILE_DESC ) { /* Needed in case starpu ask for it */
        cham_tile_interface.allocsize = tile->m * tile->n * elemsize;
    }
    else if ( tile->format & CHAMELEON_TILE_HMAT ) {
        /* For hmat, allocated data will be handled by hmat library. StarPU cannot allocate it for the library */
        cham_tile_interface.allocsize = 0;
    }

    starpu_data_register( handleptr, home_node, &cham_tile_interface, &starpu_interface_cham_tile_ops );
}

size_t
cti_handle_get_allocsize( starpu_data_handle_t handle )
{
    starpu_cham_tile_interface_t *cham_tile_interface = (starpu_cham_tile_interface_t *)
        starpu_data_get_interface_on_node( handle, STARPU_MAIN_RAM );

#ifdef STARPU_DEBUG
    STARPU_ASSERT_MSG( cham_tile_interface->id == STARPU_CHAM_TILE_INTERFACE_ID,
                       "Error. The given data is not a cham_tile." );
#endif

    return cham_tile_interface->allocsize;
}

#if defined(CHAMELEON_USE_MPI_DATATYPES)
int
cti_allocate_datatype_node( starpu_data_handle_t handle,
                            unsigned             node,
                            MPI_Datatype        *datatype )
{
    int ret;

    starpu_cham_tile_interface_t *cham_tile_interface = (starpu_cham_tile_interface_t *)
        starpu_data_get_interface_on_node( handle, node );

    size_t m  = cham_tile_interface->tile.m;
    size_t n  = cham_tile_interface->tile.n;
    size_t ld = cham_tile_interface->tile.ld;
    size_t elemsize = CHAMELEON_Element_Size( cham_tile_interface->flttype );

    ret = MPI_Type_vector( n, m * elemsize, ld * elemsize, MPI_BYTE, datatype );
    STARPU_ASSERT_MSG(ret == MPI_SUCCESS, "MPI_Type_vector failed");

    ret = MPI_Type_commit( datatype );
    STARPU_ASSERT_MSG(ret == MPI_SUCCESS, "MPI_Type_commit failed");

    return 0;
}

int
cti_allocate_datatype( starpu_data_handle_t handle,
                       MPI_Datatype        *datatype )
{
    return cti_allocate_datatype_node( handle, STARPU_MAIN_RAM, datatype );
}

void
cti_free_datatype( MPI_Datatype *datatype )
{
    MPI_Type_free( datatype );
}
#endif

void
starpu_cham_tile_interface_init()
{
    if ( starpu_interface_cham_tile_ops.interfaceid == STARPU_UNKNOWN_INTERFACE_ID )
    {
        starpu_interface_cham_tile_ops.interfaceid = starpu_data_interface_get_next_id();
#if defined(CHAMELEON_USE_MPI_DATATYPES)
  #if defined(HAVE_STARPU_MPI_INTERFACE_DATATYPE_NODE_REGISTER)
        starpu_mpi_interface_datatype_node_register( starpu_interface_cham_tile_ops.interfaceid,
                                                    cti_allocate_datatype_node,
                                                    cti_free_datatype );
  #else
        starpu_mpi_interface_datatype_register( starpu_interface_cham_tile_ops.interfaceid,
                                                cti_allocate_datatype,
                                                cti_free_datatype );
  #endif
#endif
    }
}

void
starpu_cham_tile_interface_fini()
{
    if ( starpu_interface_cham_tile_ops.interfaceid != STARPU_UNKNOWN_INTERFACE_ID )
    {
#if defined(CHAMELEON_USE_MPI_DATATYPES)
        starpu_mpi_interface_datatype_unregister( starpu_interface_cham_tile_ops.interfaceid );
#endif
    }
}