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:
| M | src/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: