rnatm

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

commit 6930b5c8dd2215a5b32eae85fe1a6c0457431df0
parent 59481826993c21a87fb6c83841ebc68447699fa1
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Tue, 23 Aug 2022 15:32:37 +0200

Sync the voxelization threads with the build thread

Diffstat:
Msrc/rnatm_octree.c | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 77 insertions(+), 8 deletions(-)

diff --git a/src/rnatm_octree.c b/src/rnatm_octree.c @@ -29,15 +29,26 @@ #include <star/svx.h> #include <rsys/clock_time.h> +#include <rsys/condition.h> #include <rsys/cstr.h> #include <rsys/double3.h> #include <rsys/math.h> #include <rsys/morton.h> +#include <rsys/mutex.h> #include <rsys/rsys.h> #include <math.h> /* lround */ #include <omp.h> +/* Structure used to synchronise the voxelization and the build threads */ +struct build_sync { + struct mutex* mutex; + struct cond* cond; + size_t ibatch; /* Index of the batch currently consumed by the build thread */ +}; +#define BUILD_SYNC_NULL__ {NULL, NULL, 0} +static const struct build_sync BUILD_SYNC_NULL = BUILD_SYNC_NULL__; + struct build_octree_context { struct pool* pool; struct partition* part; /* Current partition */ @@ -200,6 +211,34 @@ check_voxelize_args(const struct voxelize_args* args) return RES_OK; } +static void +build_sync_release(struct build_sync* sync) +{ + if(sync->mutex) mutex_destroy(sync->mutex); + if(sync->cond) cond_destroy(sync->cond); +} + +static res_T +build_sync_init(struct build_sync* sync) +{ + res_T res = RES_OK; + ASSERT(sync); + + memset(sync, 0, sizeof(*sync)); + + sync->mutex = mutex_create(); + if(!sync->mutex) { res = RES_UNKNOWN_ERR; goto error; } + sync->cond = cond_create(); + if(!sync->cond) { res = RES_UNKNOWN_ERR; goto error; } + sync->ibatch = 0; + +exit: + return res; +error: + build_sync_release(sync); + goto exit; +} + static FINLINE unsigned round_pow2(const unsigned val) { @@ -663,7 +702,10 @@ error: } static res_T -voxelize_atmosphere(struct rnatm* atm, struct pool* pool) +voxelize_atmosphere + (struct rnatm* atm, + struct pool* pool, + struct build_sync* sync) { /* Batch of spectral items to process in a single voxelization */ struct voxelize_batch_args batch_args = VOXELIZE_BATCH_ARGS_NULL; @@ -689,7 +731,7 @@ voxelize_atmosphere(struct rnatm* atm, struct pool* pool) size_t i = 0; res_T res = RES_OK; - ASSERT(atm && pool); + ASSERT(atm && pool && sync); darray_size_t_list_init(atm->allocator, &per_thread_tetra_list); darray_radcoef_list_init(atm->allocator, &per_thread_radcoef_list); @@ -761,6 +803,16 @@ voxelize_atmosphere(struct rnatm* atm, struct pool* pool) batch_args.accel_structs = accel_structs + item_range[0]; batch_args.batch_size = item_range[1] - item_range[0]; + + /* Ensure that the build thread has finished to consume the previous batch */ + mutex_lock(sync->mutex); + if(sync->ibatch != ibatch) { + ASSERT(sync->ibatch == ibatch - 1); + cond_wait(sync->cond, sync->mutex); + ASSERT(sync->ibatch == ibatch); + } + mutex_unlock(sync->mutex); + res = voxelize_batch(atm, &batch_args); if(res != RES_OK) goto error; } @@ -890,13 +942,16 @@ static res_T build_octrees (struct rnatm* atm, const struct rnatm_create_args* args, - struct pool* pool) + struct pool* pool, + struct build_sync* sync) { struct svx_device* svx = NULL; double low[3], upp[3]; size_t def[3]; size_t istruct; size_t naccel_structs; + size_t voxel_width; + ATOMIC nbuilt_structs = 0; ATOMIC res = RES_OK; ASSERT(atm && args && pool); @@ -915,10 +970,11 @@ build_octrees def[2] = (size_t)atm->grid_definition[2]; naccel_structs = darray_accel_struct_size_get(&atm->accel_structs); + voxel_width = pool_get_voxel_width(pool); /* Build the octrees. Each thread consumes an element of a partition. So, we * set the number of threads to the voxel width */ - omp_set_num_threads((int)pool_get_voxel_width(pool)); + omp_set_num_threads((int)voxel_width); #pragma omp parallel for schedule(static, 1/*chunk size*/) for(istruct = 0; istruct < naccel_structs; ++istruct) { struct build_octree_context ctx = BUILD_OCTREE_CONTEXT_NULL; @@ -931,7 +987,7 @@ build_octrees /* Setup the build context */ ctx.pool = pool; ctx.part = NULL; - ctx.iitem = istruct % pool_get_voxel_width(pool); + ctx.iitem = istruct % voxel_width; ctx.tau_threshold = args->optical_thickness; /* Setup the voxel descriptor */ @@ -945,6 +1001,15 @@ build_octrees if(ctx.part) partition_free(ctx.part); if(res_local != RES_OK) { ATOMIC_SET(&res, res_local); continue; }; + if((size_t)ATOMIC_INCR(&nbuilt_structs) % voxel_width == 0) { + /* Notify the thread voxelizing the atmospheric meshes that we are + * consuming for the next batch */ + mutex_lock(sync->mutex); + sync->ibatch += 1; + mutex_unlock(sync->mutex); + cond_signal(sync->cond); + } + /* Register the built octree */ darray_accel_struct_data_get(&atm->accel_structs)[istruct].octree = octree; } @@ -1009,6 +1074,7 @@ error: static res_T create_octrees(struct rnatm* atm, const struct rnatm_create_args* args) { + struct build_sync sync = BUILD_SYNC_NULL; struct pool* pool = NULL; const size_t bands[2] = {0,0}; /* TODO handle multiple bands */ @@ -1019,6 +1085,8 @@ create_octrees(struct rnatm* atm, const struct rnatm_create_args* args) if(res != RES_OK) goto error; res = setup_accel_structs(atm, bands); if(res != RES_OK) goto error; + res = build_sync_init(&sync); + if(res != RES_OK) goto error; log_info(atm, "partitionning of radiative properties (grid definition: %ux%ux%u)\n", SPLIT3(atm->grid_definition)); @@ -1031,9 +1099,9 @@ create_octrees(struct rnatm* atm, const struct rnatm_create_args* args) { #pragma omp section { - const res_T res_local = voxelize_atmosphere(atm, pool); + const res_T res_local = voxelize_atmosphere(atm, pool, &sync); if(res_local != RES_OK) { - log_err(atm, "error when voxelizing the atmopshere -- %s\n", + log_err(atm, "error when voxelizing the atmosphere -- %s\n", res_to_cstr((res_T)res)); pool_invalidate(pool); ATOMIC_SET(&res, res_local); @@ -1042,7 +1110,7 @@ create_octrees(struct rnatm* atm, const struct rnatm_create_args* args) #pragma omp section { - const res_T res_local = build_octrees(atm, args, pool); + const res_T res_local = build_octrees(atm, args, pool, &sync); if(res_local != RES_OK) { log_err(atm, "error building octrees -- %s\n", res_to_cstr((res_T)res)); pool_invalidate(pool); @@ -1053,6 +1121,7 @@ create_octrees(struct rnatm* atm, const struct rnatm_create_args* args) if(res != RES_OK) goto error; exit: + build_sync_release(&sync); if(pool) pool_ref_put(pool); return (res_T)res; error: