rnatm

Load and structure data describing an atmosphere
git clone git://git.meso-star.fr/rnatm.git
Log | Files | Refs | README | LICENSE

commit a2289484f1fd7d069aa9f797bc534466a6848fd9
parent 1d0d72bb32afc9da50b7c325365227d55dfcdf06
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Fri, 22 Jul 2022 09:07:35 +0200

Updating the memory layout of the voxel partition

Diffstat:
Msrc/rnatm_voxel_partition.c | 259+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Msrc/rnatm_voxel_partition.h | 68++++++++++++++++++++++++++------------------------------------------
2 files changed, 266 insertions(+), 61 deletions(-)

diff --git a/src/rnatm_voxel_partition.c b/src/rnatm_voxel_partition.c @@ -22,16 +22,50 @@ #include "rnatm_voxel_partition.h" #include <rsys/condition.h> +#include <rsys/dynamic_array_size_t.h> #include <rsys/mem_allocator.h> #include <rsys/mutex.h> #include <rsys/ref_count.h> +/* Generate the dynamic array of dynamic array of size_t */ +#define DARRAY_NAME size_t_list +#define DARRAY_DATA struct darray_size_t +#define DARRAY_FUNCTOR_INIT darray_size_t_init +#define DARRAY_FUNCTOR_RELEASE darray_size_t_release +#define DARRAY_FUNCTOR_COPY darray_size_t_copy +#define DARRAY_FUNCTOR_COPY_AND_RELEASE darray_size_t_copy_and_release +#include <rsys/dynamic_array.h> + +struct partition { + /* Size of a cluster in bytes. A cluster is a list of voxels for a quadrature + * point of a spectral band */ + size_t cluster_size; + + size_t cluster_nvoxels; /* #voxels in a cluster */ + + struct list_node node; + size_t id; /* Unique identifier of the partition */ + + /* Offset toward the voxels of a quadrature point in a spectral band. The + * first dimension corresponds to the spectral bands and the second dimension + * to the quadrature points in the spectral band */ + struct darray_size_t_list cluster_offsets; + + /* List of voxels. Use the LUT cluster_offsets to retrieve the list of voxels + * from a specific quadrature point in a given spectral band. The voxels are + * then sorted according to the morton code of the voxel coordinates */ + float* voxels; + + struct mem_allocator* allocator; + ref_T ref; +}; + struct pool { /* Linked list of pre-allocated partitions */ struct list_node parts_free; - /* List of available partition sorted in ascending order wrt partition id */ - struct list_node parts_full; + /* List of committed partition sorted in ascending order wrt partition id */ + struct list_node parts_commit; struct mutex* mutex; struct cond* cond_new; @@ -44,9 +78,101 @@ struct pool { ref_T ref; }; +static INLINE void +partition_ref_put + (struct partition* partition); + /******************************************************************************* * Helper functions ******************************************************************************/ +static INLINE res_T +check_pool_create_args(const struct pool_create_args* args) +{ + size_t iband; + + if(!args + || !args->npartitions + || !args->nbands + || !args->nquad_pts + || !IS_POW2(args->partition_definition)) { + return RES_BAD_ARG; + } + + FOR_EACH(iband, 0, args->nbands) { + const size_t nquad_pts = args->nquad_pts(iband, args->context); + if(!nquad_pts) return RES_BAD_ARG; + } + + return RES_OK; +} + +static res_T +setup_partition_clusters + (struct partition* partition, + const struct pool_create_args* args) +{ + size_t nclusters = 0; + size_t iband = 0; + res_T res = RES_OK; + ASSERT(partition && args); + + /* Compute the size of a cluster. Ensure a multiple of 64 bytes, i.e. align + * the cluster of voxels on the size of a cache line */ + partition->cluster_nvoxels = + args->partition_definition + * args->partition_definition + * args->partition_definition; + partition->cluster_size = ALIGN_SIZE + (partition->cluster_nvoxels * NFLOATS_PER_VOXEL * sizeof(float), 64u); + + /* Allocate the list of per band cluster offsets */ + res = darray_size_t_list_resize(&partition->cluster_offsets, args->nbands); + if(res != RES_OK) goto error; + + FOR_EACH(iband, 0, args->nbands) { + struct darray_size_t* offsets = NULL; + const size_t nquad_pts = args->nquad_pts(iband, args->context); + size_t iquad_pt = 0; + + /* Allocate the cluster offsets for the quadrature points of the band */ + offsets = darray_size_t_list_data_get(&partition->cluster_offsets) + iband; + res = darray_size_t_resize(offsets, nquad_pts); + if(res != RES_OK) goto error; + + /* Setup the cluster offsets for the quadrature points of the band */ + FOR_EACH(iquad_pt, 0, nquad_pts) { + darray_size_t_data_get(offsets)[iquad_pt] = + nclusters * partition->cluster_size; + nclusters += 1; + } + } + + /* Allocate the whole set of clusters */ + partition->voxels = MEM_ALLOC_ALIGNED + (partition->allocator, nclusters*partition->cluster_size, 64); + if(!partition->voxels) { res = RES_MEM_ERR; goto error; } + +exit: + return res; +error: + darray_size_t_list_clear(&partition->cluster_offsets); + if(partition->voxels) { + MEM_RM(partition->allocator, partition->voxels); + partition->voxels = NULL; + } + goto exit; +} + +static void +release_partition(ref_T* ref) +{ + struct partition* partition = CONTAINER_OF(ref, struct partition, ref); + ASSERT(partition && is_list_empty(&partition->node)); + if(partition->voxels) MEM_RM(partition->allocator, partition->voxels); + darray_size_t_list_release(&partition->cluster_offsets); + MEM_RM(partition->allocator, partition); +} + static void release_pool(ref_T* ref) { @@ -62,37 +188,134 @@ release_pool(ref_T* ref) LIST_FOR_EACH_SAFE(node, tmp_node, &pool->parts_free) { struct partition* partition = CONTAINER_OF(node, struct partition, node); list_del(node); - partition_release(partition); + partition_ref_put(partition); MEM_RM(pool->allocator, partition); } - LIST_FOR_EACH_SAFE(node, tmp_node, &pool->parts_full) { + LIST_FOR_EACH_SAFE(node, tmp_node, &pool->parts_commit) { struct partition* partition = CONTAINER_OF(node, struct partition, node); list_del(node); - partition_release(partition); + partition_ref_put(partition); MEM_RM(pool->allocator, partition); } ASSERT(is_list_empty(&pool->parts_free)); - ASSERT(is_list_empty(&pool->parts_full)); + ASSERT(is_list_empty(&pool->parts_commit)); +} + +/******************************************************************************* + * Partition of voxels + ******************************************************************************/ +static res_T +partition_create + (const struct pool_create_args* args, + struct partition** out_partition) +{ + struct partition* partition = NULL; + struct mem_allocator* allocator = NULL; + res_T res = RES_OK; + ASSERT(check_pool_create_args(args) == RES_OK && out_partition); + + allocator = args->allocator ? args->allocator : &mem_default_allocator; + partition = MEM_CALLOC(allocator, 1, sizeof(*partition)); + if(!partition) { + res = RES_MEM_ERR; + goto error; + } + partition->allocator = allocator; + ref_init(&partition->ref); + list_init(&partition->node); + partition->id = SIZE_MAX; + darray_size_t_list_init(partition->allocator, &partition->cluster_offsets); + + res = setup_partition_clusters(partition, args); + if(res != RES_OK) goto error; + +exit: + *out_partition = partition; + return res; +error: + if(partition) partition_ref_put(partition); + goto exit; +} + +static INLINE void +partition_ref_get(struct partition* partition) +{ + ASSERT(partition); + ref_get(&partition->ref); +} + +void +partition_ref_put(struct partition* partition) +{ + ASSERT(partition); + ref_put(&partition->ref, release_partition); +} + +float* +partition_get_voxel + (struct partition* part, + const size_t iband, + const size_t iquad_pt, + const size_t ivoxel) +{ + const struct darray_size_t* band_offsets = NULL; + size_t offset = 0; + ASSERT(part); + ASSERT(iband < darray_size_t_list_size_get(&part->cluster_offsets)); + ASSERT(ivoxel < part->cluster_nvoxels); + + /* Fetch the offset toward the list of voxels of the quadrature point of the + * given spectral band */ + band_offsets = darray_size_t_list_cdata_get(&part->cluster_offsets)+iband; + ASSERT(iquad_pt < darray_size_t_size_get(band_offsets)); + offset = darray_size_t_cdata_get(band_offsets)[iquad_pt]; + + return part->voxels + offset + ivoxel; +} + +void +partition_clear_voxels(struct partition* partition) +{ + size_t iband, nbands; + ASSERT(partition); + + nbands = darray_size_t_list_size_get(&partition->cluster_offsets); + + FOR_EACH(iband, 0, nbands) { + const struct darray_size_t* band_offsets; + size_t iquad_pt, nquad_pts; + + band_offsets = darray_size_t_list_cdata_get(&partition->cluster_offsets)+iband; + nquad_pts = darray_size_t_size_get(band_offsets); + + FOR_EACH(iquad_pt, 0, nquad_pts) { + size_t ivoxel = 0; + + FOR_EACH(ivoxel, 0, partition->cluster_nvoxels) { + float* voxel = partition_get_voxel(partition, iband, iquad_pt, ivoxel); + voxel_clear(voxel); + } + } + } } /******************************************************************************* - * Local functions + * Pool of partitions ******************************************************************************/ res_T pool_create - (struct mem_allocator* mem_allocator, - const size_t npartitions, + (const struct pool_create_args* args, struct pool** out_pool) { struct mem_allocator* allocator = NULL; struct pool* pool = NULL; size_t ipartition = 0; res_T res = RES_OK; - ASSERT(out_pool && npartitions); + ASSERT(check_pool_create_args(args) == RES_OK && out_pool); - allocator = mem_allocator ? mem_allocator : &mem_default_allocator; + allocator = args->allocator ? args->allocator : &mem_default_allocator; pool = MEM_CALLOC(allocator, 1, sizeof(*pool)); if(!pool) { res = RES_MEM_ERR; @@ -101,7 +324,7 @@ pool_create pool->allocator = allocator; ref_init(&pool->ref); list_init(&pool->parts_free); - list_init(&pool->parts_full); + list_init(&pool->parts_commit); /* Create the mutex and condition variables used to synchronize threads */ pool->mutex = mutex_create(); @@ -112,14 +335,12 @@ pool_create if(!pool->cond_fetch) { res = RES_UNKNOWN_ERR; goto error; } /* Pre-allocate the partitions */ - FOR_EACH(ipartition, 0, npartitions) { + FOR_EACH(ipartition, 0, args->npartitions) { struct partition* partition = NULL; - /* Aligns the partition on 64 Bytes (i.e. the size of a cache line) */ - partition = MEM_ALLOC_ALIGNED(pool->allocator, sizeof(*partition), 64); - if(!partition) { res = RES_MEM_ERR; goto error; } + res = partition_create(args, &partition); + if(res != RES_OK) goto error; - partition_init(partition); list_add(&pool->parts_free, &partition->node); } @@ -203,7 +424,7 @@ pool_commit_partition(struct pool* pool, struct partition* partition) * therefore looking for the partition whose id is less than the id of the * partition to be committed in order to add the latter in the right place */ mutex_lock(pool->mutex); - LIST_FOR_EACH_REVERSE(node, &pool->parts_full) { + LIST_FOR_EACH_REVERSE(node, &pool->parts_commit) { struct partition* partition2 = CONTAINER_OF(node, struct partition, node); if(partition2->id < partition->id) break; } @@ -225,7 +446,7 @@ pool_fetch_partition(struct pool* pool, const size_t ipartition) while(!pool->error) { /* Finds the partition that matches the submitted id */ - LIST_FOR_EACH(node, &pool->parts_full) { + LIST_FOR_EACH(node, &pool->parts_commit) { struct partition* partition = CONTAINER_OF(node, struct partition, node); /* The partition to fetch has been found */ diff --git a/src/rnatm_voxel_partition.h b/src/rnatm_voxel_partition.h @@ -34,61 +34,45 @@ * PARTITION_DEFINITION \ * PARTITION_DEFINITION) -/****************************************************************************** - * Partition of voxels, i.e. collection of three-dimensional arrays of voxels - ******************************************************************************/ -struct partition { - /* Voxels ordered wrt their Morton code */ - float voxels[PARTITION_NVOXELS * NFLOATS_PER_VOXEL]; +struct pool_create_args { + size_t npartitions; /* Number of partitions to preallocate */ - struct list_node node; - size_t id; /* Unique identifier of the partition */ + size_t nbands; /* Number of spectral band per partition */ + size_t (*nquad_pts)(const size_t iband, void* ctx); /* #quad pts per band */ + void* context; /* User data sent as the last argument of the functor */ + size_t partition_definition; /* #voxels along XYZ. Must be a power of 2 */ + + struct mem_allocator* allocator; /* NULL <=> default allocator */ }; +#define POOL_CREATE_ARGS_DEFAULT__ {0, 0, NULL, NULL, 0, NULL} +static const struct pool_create_args POOL_CREATE_ARGS_DEFAULT = + POOL_CREATE_ARGS_DEFAULT__; + +/****************************************************************************** + * Partition of voxels, i.e. subset of voxels + ******************************************************************************/ +struct partition; -static INLINE void -partition_init(struct partition* partition) -{ - ASSERT(partition); - list_init(&partition->node); - partition->id = SIZE_MAX; -} - -static INLINE void -partition_release(struct partition* partition) -{ - ASSERT(partition && is_list_empty(&partition->node)); - (void)partition; /* Nothing to do */ -} - -static FINLINE float* +extern LOCAL_SYM FINLINE float* partition_get_voxel (struct partition* partition, - const size_t ivoxel) /* Morton code of the voxel */ -{ - ASSERT(partition && ivoxel < PARTITION_NVOXELS); - return partition->voxels + ivoxel * NFLOATS_PER_VOXEL; -} - -static INLINE void -partition_clear_voxels(struct partition* partition) -{ - size_t ivoxel; - FOR_EACH(ivoxel, 0, PARTITION_NVOXELS) { - float* voxel = partition_get_voxel(partition, ivoxel); - voxel_clear(voxel); - } -} + const size_t iband, + const size_t iquad_pt, + const size_t ivoxel); + +extern LOCAL_SYM void +partition_clear_voxels + (struct partition* partition); /****************************************************************************** - * Partition pool, i.e. collection of partitions of voxels that accessible + * Partition pool, i.e. collection of partitions of voxels that are accessible * concurrently by several threads ******************************************************************************/ struct pool; extern LOCAL_SYM res_T pool_create - (struct mem_allocator* allocator, /* May be NULL <=> default allocator */ - const size_t npartitions, /* #partitions managed by the pool */ + (const struct pool_create_args* args, struct pool** pool); extern LOCAL_SYM void