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:
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