commit e0c41bfab79971106eb4112763b0a8facdbdb92a
parent d030170bf319776fb481c0cda38cba6ab67d1a13
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Mon, 29 Aug 2022 16:50:22 +0200
Begin the implementation of octree offloading
Diffstat:
4 files changed, 176 insertions(+), 5 deletions(-)
diff --git a/src/rnatm.c b/src/rnatm.c
@@ -450,6 +450,7 @@ accel_struct_init
accel_struct->octree = NULL;
accel_struct->iband = 0;
accel_struct->iquad_pt = 0;
+ memset(&accel_struct->fpos, 0, sizeof(accel_struct->fpos));
return RES_OK;
}
@@ -466,6 +467,7 @@ accel_struct_copy(struct accel_struct* dst, const struct accel_struct* src)
ASSERT(dst && src);
if(dst->octree) SVX(tree_ref_put(dst->octree));
dst->octree = src->octree;
+ dst->fpos = src->fpos;
dst->iband = src->iband;
dst->iquad_pt = src->iquad_pt;
if(dst->octree) SVX(tree_ref_get(dst->octree));
@@ -478,6 +480,7 @@ accel_struct_copy_and_release(struct accel_struct* dst, struct accel_struct* src
ASSERT(dst && src);
if(dst->octree) SVX(tree_ref_put(dst->octree));
dst->octree = src->octree;
+ dst->fpos = src->fpos;
dst->iband = src->iband;
dst->iquad_pt = src->iquad_pt;
src->octree = NULL;
diff --git a/src/rnatm.h b/src/rnatm.h
@@ -85,6 +85,8 @@ struct rnatm_create_args {
size_t naerosols;
char* name; /* Name of the atmosphere */
+ FILE* octrees_storage; /* File where octrees are serialized. May be NULL */
+
/* Spectral range to consider (in wavenumbers). Limits are inclusive */
double spectral_range[2];
double optical_thickness; /* Threshold used during octree building */
@@ -104,6 +106,8 @@ struct rnatm_create_args {
0, /* Number of aerosols */ \
"atmosphere", /* Name */ \
\
+ NULL, /* octrees storage */ \
+ \
{12820.513, 26315.789}, /* Spectral range */ \
1, /* Optical thickness */ \
\
diff --git a/src/rnatm_c.h b/src/rnatm_c.h
@@ -144,6 +144,7 @@ aerosol_copy_and_release
******************************************************************************/
struct accel_struct {
struct svx_tree* octree;
+ fpos_t fpos; /* Position of the serialized data in the storage file */
size_t iband; /* Index of the spectral band */
size_t iquad_pt; /* Index of the quadrature point */
};
@@ -194,6 +195,7 @@ struct rnatm {
struct logger logger__;
struct mem_allocator* allocator;
struct mem_allocator svx_allocator;
+
int svx_allocator_is_init;
ref_T ref;
};
diff --git a/src/rnatm_octree.c b/src/rnatm_octree.c
@@ -18,7 +18,8 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
-#define _POSIX_C_SOURCE 200112L /* lround and nextafter support */
+/* lround, nextafter */
+#define _POSIX_C_SOURCE 200112L
#include "rnatm_c.h"
#include "rnatm_log.h"
@@ -54,6 +55,13 @@ struct build_sync {
#define BUILD_SYNC_NULL__ {NULL, NULL, 0}
static const struct build_sync BUILD_SYNC_NULL = BUILD_SYNC_NULL__;
+struct storage {
+ FILE* fp; /* File pointer */
+ fpos_t header; /* Position of the header */
+};
+#define STORAGE_NULL__ {NULL}
+static const struct storage STORAGE_NULL = STORAGE_NULL__;
+
struct build_octree_context {
struct pool* pool;
struct partition* part; /* Current partition */
@@ -517,10 +525,10 @@ setup_tetra_radcoefs_aerosol
/* TODO ask VE what to do if:
* - the spectral meshes have holes
- * - no aerosol band is overlaid by the gas band
- * - the aerosol bands are entirely included in the gas band
- * - gas/an aerosol band is degenerated (i.e. lower == upper)
- * - the gas band and aerosol band are the same */
+ * - no aerosol band is overlaid by the gas band => FIXME no aerosol
+ * - the aerosol bands are entirely included in the gas band FIXME general case
+ * - gas degenerated => FIXME the aerosol bands must include the gas band
+ * - the gas band and aerosol band are the same => FIXME take the aerosol properties */
/* Aerosol spectral data is not overlaid by the gas band */
if(ars_ibands[0] > ars_ibands[1]) FATAL("Not implemented yet!\n");
@@ -531,6 +539,7 @@ setup_tetra_radcoefs_aerosol
if(ars_ibands[0] == ars_ibands[1]
&& ars_band.lower <= gas_band.lower
&& ars_band.upper >= gas_band.upper) {
+ /* FIXME use the aerosole properties */
setup_tetra_radcoefs_gas(atm, tetra, iband, iquad_pt, radcoefs);
/* The gas band overlaid N aerosol bands (N >= 1) */
@@ -541,6 +550,8 @@ setup_tetra_radcoefs_aerosol
float rcp_gas_band_len;
size_t iars_band;
+ /* TODO If gas.lambda_min == gas.lambda_max use the properties of the
+ * aerosol band */
FOR_EACH(iars_band, ars_ibands[0], ars_ibands[1]+1) {
double lambda_min;
double lambda_max;
@@ -1166,12 +1177,148 @@ vx_challenge_merge
}
static res_T
+storage_init
+ (struct rnatm* atm,
+ const struct rnatm_create_args* args,
+ struct storage* storage)
+{
+ size_t noctrees = 0;
+ size_t header_size = 0;
+ int err = 0;
+ res_T res = RES_OK;
+
+ ASSERT(atm && args && storage);
+
+ if(!args->octrees_storage) { /* No octrees storage */
+ *storage = STORAGE_NULL;
+ goto exit;
+ }
+
+ noctrees = darray_accel_struct_size_get(&atm->accel_structs);
+
+ storage->fp = args->octrees_storage;
+
+ err = fgetpos(storage->fp, &storage->header);
+ if(err != 0) { res = RES_IO_ERR; goto error; }
+
+ /* Compute the header size */
+ header_size =
+ sizeof(size_t)/*#octrees*/
+ + sizeof(fpos_t)*noctrees; /* Table of offsets */
+ ASSERT(header_size < LONG_MAX);
+
+ /* Reserve the space for the header */
+ err = fseek(storage->fp, (long)header_size, SEEK_CUR);
+ if(err != 0) { res = RES_IO_ERR; goto error; }
+
+exit:
+ return res;
+error:
+ log_err(atm, "error initializing disk storage of octrees -- %s\n",
+ strerror(errno));
+ goto exit;
+}
+
+static res_T
+storage_write_octrees
+ (struct rnatm* atm,
+ const struct storage* storage,
+ const size_t ioctrees[2]) /* Octrees to write. Limits are inclusive */
+{
+ size_t ioctree = 0;
+ int err = 0;
+ res_T res = RES_OK;
+ ASSERT(atm && storage && ioctrees && ioctrees[0] <= ioctrees[1]);
+ ASSERT(ioctrees[1] < darray_accel_struct_size_get(&atm->accel_structs));
+
+ /* No storage: nothing to do */
+ if(!storage->fp) goto exit;
+
+ FOR_EACH(ioctree, ioctrees[0], ioctrees[1]+1) {
+ struct accel_struct* accel_struct = NULL;
+ accel_struct = darray_accel_struct_data_get(&atm->accel_structs) + ioctree;
+
+ /* Save the current file offset */
+ err = fgetpos(storage->fp, &accel_struct->fpos);
+ if(err != 0) {
+ log_err(atm, "error retrieving octree storage position -- %s\n",
+ strerror(errno));
+ res = RES_IO_ERR;
+ goto error;
+ }
+
+ /* Serialize the octree */
+ res = svx_tree_write(accel_struct->octree, storage->fp);
+ if(res != RES_OK) {
+ log_err(atm, "error serializing octree %lu -- %s\n",
+ (unsigned long)ioctree, res_to_cstr(res));
+ goto error;
+ }
+
+ /* Free the octree memory */
+ SVX(tree_ref_put(accel_struct->octree));
+ accel_struct->octree = NULL;
+ }
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
+storage_finalize(struct rnatm* atm, struct storage* storage)
+{
+ size_t naccel_structs = 0;
+ size_t iaccel_struct = 0;
+ int err = 0;
+ res_T res = RES_OK;
+ ASSERT(atm && storage);
+
+ /* No storage: nothing to do */
+ if(storage->fp) goto exit;
+
+ err = fsetpos(storage->fp, &storage->header);
+ if(err != 0) {
+ log_err(atm, "error positioning on octree storage header -- %s\n",
+ strerror(errno));
+ res = RES_IO_ERR;
+ goto error;
+ }
+
+ naccel_structs = darray_accel_struct_size_get(&atm->accel_structs);
+
+ /* Write the number of voxelized octrees and their corresponding offset */
+ #define WRITE(Var) { \
+ if(fwrite((Var), sizeof(*(Var)), 1, storage->fp) != 1) { \
+ log_err(atm, "error serializing octree storage header\n"); \
+ res = RES_IO_ERR; \
+ goto error; \
+ } \
+ } (void)0
+
+ WRITE(&naccel_structs);
+ FOR_EACH(iaccel_struct, 0, naccel_structs) {
+ const struct accel_struct* accel_struct =
+ darray_accel_struct_cdata_get(&atm->accel_structs) + iaccel_struct;
+ WRITE(&accel_struct->fpos);
+ }
+ #undef WRITE
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
build_octrees
(struct rnatm* atm,
const struct rnatm_create_args* args,
struct pool* pool,
struct build_sync* sync)
{
+ struct storage storage = STORAGE_NULL;
struct svx_device* svx = NULL;
struct accel_struct* accel_structs = NULL;
double low[3], upp[3];
@@ -1200,6 +1347,10 @@ build_octrees
naccel_structs = darray_accel_struct_size_get(&atm->accel_structs);
voxel_width = pool_get_voxel_width(pool);
+ /* Setup the disk storage of the octrees */
+ res = storage_init(atm, args, &storage);
+ if(res != RES_OK) goto error;
+
/* Build the octrees. Each thread consumes an element of the voxels generated
* by the voxelization thread, each element corresponding to the voxel of an
* octree to be constructed. By fixing the number of threads to the width of
@@ -1207,6 +1358,7 @@ build_octrees
* single voxelization of the atmospheric meshes */
for(istruct = 0; istruct < naccel_structs; istruct += voxel_width) {
const size_t batch_size = MMIN(voxel_width, naccel_structs - istruct);
+ size_t ioctrees[2];
omp_set_num_threads((int)batch_size);
/* Note that we are using a parallel block rather than a parallel loop in
@@ -1250,8 +1402,18 @@ build_octrees
sync->ibatch += 1;
mutex_unlock(sync->mutex);
cond_signal(sync->cond);
+
+ /* Offload builded octrees */
+ ioctrees[0] = istruct;
+ ioctrees[1] = istruct + batch_size - 1;
+ res = storage_write_octrees(atm, &storage, ioctrees);
+ if(res != RES_OK) goto error;
}
+ /* Finalize the file where octrees are offloaded */
+ res = storage_finalize(atm, &storage);
+ if(res != RES_OK) goto error;
+
exit:
if(svx) SVX(device_ref_put(svx));
return (res_T)res;