star-schiff

Library for estimating radiative properties
git clone git://git.meso-star.com/star-schiff.git
Log | Files | Refs | README | LICENSE

commit 77edf63c29c2e419a4c2181c0bd667d22fbc1c7b
parent 09d41005bf1e10d656a5ff24d59be799cc6d4720
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Tue, 24 Nov 2015 15:15:18 +0100

Add multi-threaded support to the Schiff integration

Update the sschiff_device_create API to handle an hint on the number of
threads to use during the Schiff integration. The number of threads that
is effectively use is the minimum between the submitted hint and the
number of CPU cores. One can use the macro SSCHIFF_NTHREADS_DEFAULT to
use as many threads as CPU cores.

Note that when no Star-3D device is submitted on the creation of the
Star-Schiff device, best performances are obtained by creating as many
Star-3D device as threads; the Star-3D back-end (i.e. embree) seems to
perform some synchronisations - leading to performance loss - when
several acceleration data structures are built on the same device.

Diffstat:
Mcmake/CMakeLists.txt | 12++++++++++++
Msrc/sschiff.h | 5++++-
Msrc/sschiff_device.c | 52++++++++++++++++++++++++++++++++++++++++------------
Msrc/sschiff_device.h | 3++-
Msrc/sschiff_estimator.c | 266++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Msrc/test_sschiff_device.c | 25+++++++++++++++----------
Msrc/test_sschiff_estimator_cylinder.c | 3++-
Msrc/test_sschiff_estimator_sphere.c | 3++-
8 files changed, 252 insertions(+), 117 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -40,6 +40,11 @@ find_package(RCMake 0.2.1 REQUIRED) find_package(RSys 0.3 REQUIRED) find_package(StarSP 0.3 REQUIRED) find_package(Star3D 0.3 REQUIRED) +find_package(OpenMP 1.2 REQUIRED) + +if(NOT OPENMP_FOUND) + message(STATUS "No OpenMP support: muti-threading is disabled") +endif() include_directories( ${RSys_INCLUDE_DIR} @@ -80,6 +85,13 @@ if(CMAKE_COMPILER_IS_GNUCC) target_link_libraries(sschiff m) endif() +set_target_properties(sschiff PROPERTIES + COMPILE_FLAGS ${OpenMP_C_FLAGS} + COMPILE_DEFINITIONS SSCHIFF_USE_OPENMP) +if(CMAKE_COMPILER_IS_GNUCC) + set_target_properties(sschiff PROPERTIES LINK_FLAGS ${OpenMP_C_FLAGS}) +endif() + rcmake_setup_devel(sschiff StarSchiff ${VERSION} star/sschiff_version.h) ################################################################################ diff --git a/src/sschiff.h b/src/sschiff.h @@ -49,6 +49,8 @@ #define SSCHIFF(Func) sschiff_ ## Func #endif +#define SSCHIFF_NTHREADS_DEFAULT (~0u) + /* Forward declaration of external types. */ struct mem_allocator; struct logger; @@ -121,7 +123,8 @@ SSCHIFF_API res_T sschiff_device_create (struct logger* logger, /* May be NULL <=> use default logger */ struct mem_allocator* allocator, /* May be NULL <=> use default allocator */ - const int verbose, + const unsigned nthreads_hint, /* Hint on the number of threads to use */ + const int verbose, /* Make the command more verbose */ struct s3d_device* s3d, /* May be NULL <=> internally create a S3D device */ struct sschiff_device** dev); diff --git a/src/sschiff_device.c b/src/sschiff_device.c @@ -31,11 +31,14 @@ #include <rsys/logger.h> #include <rsys/mem_allocator.h> +#include <rsys/stretchy_array.h> #include <star/s3d.h> #include <stdarg.h> +#include <omp.h> + /******************************************************************************* * Helper function ******************************************************************************/ @@ -45,7 +48,13 @@ device_release(ref_T* ref) struct sschiff_device* dev; ASSERT(ref); dev = CONTAINER_OF(ref, struct sschiff_device, ref); - if(dev) S3D(device_ref_put(dev->s3d)); + if(dev->s3d) { + size_t i; + FOR_EACH(i, 0, dev->nthreads) { + if(dev->s3d[i]) S3D(device_ref_put(dev->s3d[i])); + } + sa_release(dev->s3d); + } MEM_RM(dev->allocator, dev); } @@ -66,7 +75,6 @@ log_error(struct sschiff_device* dev, const char* msg, ...) } } - /******************************************************************************* * API functions ******************************************************************************/ @@ -74,6 +82,7 @@ res_T sschiff_device_create (struct logger* log, struct mem_allocator* allocator, + const unsigned nthreads_hint, const int verbose, struct s3d_device* s3d, struct sschiff_device** out_dev) @@ -81,9 +90,10 @@ sschiff_device_create struct mem_allocator* mem_allocator; struct sschiff_device* dev = NULL; struct logger* logger = NULL; + size_t i; res_T res = RES_OK; - if(!out_dev) { + if(!out_dev || !nthreads_hint) { res = RES_BAD_ARG; goto error; } @@ -101,19 +111,37 @@ sschiff_device_create dev->allocator = mem_allocator; dev->logger = logger; dev->verbose = verbose; + dev->nthreads = MMIN(nthreads_hint, (unsigned)omp_get_num_procs()); - if(s3d) { - S3D(device_ref_get(s3d)); - dev->s3d = s3d; - } else { - res = s3d_device_create(dev->logger, dev->allocator, 0, &dev->s3d); - if(res != RES_OK) { - log_error - (dev, "Couldn't create the internal Star-3D device of Star-Schiff.\n"); - goto error; + if(!sa_add(dev->s3d, dev->nthreads)) { + log_error(dev, + "Not enough memory: couldn't allocate the list of S3D devices.\n"); + res = RES_MEM_ERR; + goto error; + } + memset(dev->s3d, 0, sizeof(struct s3d_device*)*dev->nthreads); + + FOR_EACH(i, 0, dev->nthreads) { + if(s3d) { + S3D(device_ref_get(s3d)); + dev->s3d[i] = s3d; + } else { + /* Create as many Star-3D devices as threads since this is actually more + * efficient. It seems that the Star-3D back-end (i.e. embree) shared + * some ressources - and thus perform some synchronisations leading to + * performance loss - if several acceleration data structures are build + * on the same device. */ + res = s3d_device_create(dev->logger, dev->allocator, 0, &dev->s3d[i]); + if(res != RES_OK) { + log_error + (dev, "Couldn't create the internal Star-3D device of Star-Schiff.\n"); + goto error; + } } } + omp_set_num_threads((int)dev->nthreads); + exit: if(out_dev) *out_dev = dev; return res; diff --git a/src/sschiff_device.h b/src/sschiff_device.h @@ -37,8 +37,9 @@ struct s3d_device; struct sschiff_device { int verbose; + unsigned nthreads; struct logger* logger; - struct s3d_device* s3d; + struct s3d_device** s3d; struct mem_allocator* allocator; ref_T ref; diff --git a/src/sschiff_estimator.c b/src/sschiff_estimator.c @@ -31,7 +31,6 @@ #include "sschiff.h" #include "sschiff_device.h" -#include <rsys/dynamic_array_double.h> #include <rsys/float2.h> #include <rsys/float3.h> #include <rsys/image.h> @@ -44,6 +43,7 @@ #include <star/ssp.h> #include <math.h> +#include <omp.h> #define MAX_FAILURES 10 @@ -61,21 +61,9 @@ struct mc_accum { struct mc_data mc_data[SSCHIFF_DATA_COUNT__]; }; static const struct mc_accum MC_ACCUM_NULL = {{{0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}, {0.0, 0.0}}}; -#define DARRAY_NAME mcaccum -#define DARRAY_DATA struct mc_accum -#include <rsys/dynamic_array.h> - -#define DARRAY_NAME accum -#define DARRAY_DATA struct accum -#include <rsys/dynamic_array.h> - -#define DARRAY_NAME mtl -#define DARRAY_DATA struct sschiff_material_properties -#include <rsys/dynamic_array.h> - struct sschiff_estimator { - struct darray_double wavelengths; - struct darray_mcaccum accums; + double* wavelengths; + struct mc_accum* accums; struct sschiff_device* dev; size_t nrealisations; ref_T ref; @@ -281,7 +269,7 @@ accum_monte_carlo_weight (struct sschiff_device* dev, struct s3d_scene* scn, struct ssp_rng* rng, - struct sschiff_material_properties* props, + const struct sschiff_material_properties* props, const double* wavelengths, /* In micron */ const size_t nwavelengths, const float basis[9], /* World space basis of the RT volume */ @@ -384,7 +372,7 @@ radiative_properties const size_t nwavelengths, const size_t ndirs, struct s3d_scene* scene, - struct sschiff_material_properties* props, + const struct sschiff_material_properties* props, struct mc_accum* mc_accums, struct accum* accums) { @@ -501,8 +489,8 @@ estimator_release(ref_T* ref) ASSERT(ref); estimator = CONTAINER_OF(ref, struct sschiff_estimator, ref); dev = estimator->dev; - darray_double_release(&estimator->wavelengths); - darray_mcaccum_release(&estimator->accums); + if(estimator->wavelengths) sa_release(estimator->wavelengths); + if(estimator->accums) sa_release(estimator->accums); MEM_RM(dev->allocator, estimator); SSCHIFF(device_ref_put(dev)); } @@ -527,20 +515,17 @@ estimator_create ref_init(&estimator->ref); SSCHIFF(device_ref_get(dev)); estimator->dev = dev; - darray_double_init(dev->allocator, &estimator->wavelengths); - darray_mcaccum_init(dev->allocator, &estimator->accums); - res = darray_double_resize(&estimator->wavelengths, nwavelengths); - if(res != RES_OK) { + if(!sa_add(estimator->wavelengths, nwavelengths)) { log_error(dev, - "Not enough memory: couldn't allocate the list of wavelengths.\n"); + "Not enough memory: couldn't allocate the list of estimated wavelengths.\n"); + res = RES_MEM_ERR; goto error; } - res = darray_mcaccum_resize(&estimator->accums, nwavelengths); - if(res != RES_OK) { + if(!sa_add(estimator->accums, nwavelengths)) { log_error(dev, - "Not enough memory: couldn't allocate the per wavelength " - "Monte Carlo accumulators.\n"); + "Not enough memory: couldn't allocate the Monte Carlo accumulator.\n"); + res = RES_MEM_ERR; goto error; } @@ -570,11 +555,14 @@ sschiff_integrate const size_t ndirs, struct sschiff_estimator** out_estimator) { - struct darray_mtl mtls; - struct darray_accum accums; + struct sschiff_material_properties** mtls = NULL; + struct accum** accums = NULL; + struct mc_accum** mc_accums = NULL; struct sschiff_estimator* estimator = NULL; - struct s3d_shape* shape = NULL; - struct s3d_scene* scene = NULL; + struct s3d_shape** shapes = NULL; + struct s3d_scene** scenes = NULL; + struct ssp_rng** rngs = NULL; + struct ssp_rng_proxy* rng_proxy = NULL; size_t i; res_T res = RES_OK; (void)nangles; @@ -584,94 +572,190 @@ sschiff_integrate return RES_BAD_ARG; } - darray_mtl_init(dev->allocator, &mtls); - darray_accum_init(dev->allocator, &accums); + res = estimator_create(dev, nwavelengths, &estimator); + if(res != RES_OK) goto error; + estimator->nrealisations = ngeoms; - res = darray_mtl_resize(&mtls, nwavelengths); + res = ssp_rng_proxy_create_from_rng + (dev->allocator, rng, dev->nthreads, &rng_proxy); if(res != RES_OK) { + log_error(dev, "Couldn't create the proxy allocator\n"); + goto error; + } + /* Create the containers of per thread data structures */ + if(!sa_add(mtls, dev->nthreads)) { log_error(dev, - "No enough memory: couldn't allocate the per wavelength" - "optical properties.\n"); + "No enough memory: couldn't allocate the list of optical properties.\n"); + res = RES_MEM_ERR; goto error; } - - res = darray_accum_resize(&accums, nwavelengths); - if(res != RES_OK) { + if(!sa_add(accums, dev->nthreads)) { log_error(dev, - "No enough memory: couldn't allocate the per wavelength " - "temporary accumulators.\n"); + "No enough memory: couldn't allocate the list of temporary accumulators.\n"); + res = RES_MEM_ERR; goto error; } - - res = estimator_create(dev, nwavelengths, &estimator); - if(res != RES_OK) goto error; - estimator->nrealisations = ngeoms; - - res = s3d_shape_create_mesh(dev->s3d, &shape); - if(res != RES_OK) { - log_error(dev, "Couldn't create the Star-3D Schiff shape.\n"); + if(!sa_add(mc_accums, dev->nthreads)) { + log_error(dev, + "Not enough memory: couldn't allocate the list Monte Carlo accumulators.\n"); + res = RES_MEM_ERR; goto error; } - res = s3d_scene_create(dev->s3d, &scene); - if(res != RES_OK) { - log_error(dev, "Couldn't create the Star-3D Schiff scene.\n"); + if(!sa_add(rngs, dev->nthreads)) { + log_error(dev, + "Not enough memory: couldn't allocate the list of RNGs.\n"); + } + if(!sa_add(scenes, dev->nthreads)) { + log_error(dev, + "Not enough memory: couldn't allocate the list of Star-3D scenes.\n"); + res = RES_MEM_ERR; goto error; } - res = s3d_scene_attach_shape(scene, shape); - if(res != RES_OK) { + if(!sa_add(shapes, dev->nthreads)) { log_error(dev, - "Couldn't attach the Star-3D Schiff shape to the Star-3D Schiff scene.\n"); + "Not enough memory: couldn't allocate the list of Star-3D shapes.\n"); + res = RES_MEM_ERR; goto error; } + memset(mtls, 0, sizeof(struct sschiff_material_properties*)*dev->nthreads); + memset(accums, 0, sizeof(struct accum*)*dev->nthreads); + memset(mc_accums, 0, sizeof(struct mc_accum*)*dev->nthreads); + memset(rngs, 0, sizeof(struct ssp_rng*)*dev->nthreads); + memset(scenes, 0, sizeof(struct s3d_scene*)*dev->nthreads); + memset(shapes, 0, sizeof(struct s3d_shapes*)*dev->nthreads); + + /* Create the per thread data structures */ + FOR_EACH(i, 0, dev->nthreads) { + if(!sa_add(mtls[i], nwavelengths)) { + log_error(dev, + "Not enough memory: couldn't allocate the optical properties.\n"); + res = RES_MEM_ERR; + goto error; + } + if(!sa_add(accums[i], nwavelengths)) { + log_error(dev, + "Not enough memory: couldn't allocate the temporary accumulator.\n"); + res = RES_MEM_ERR; + goto error; + } + if(!sa_add(mc_accums[i], nwavelengths)) { + log_error(dev, + "Not enough memory: couldn't allocate the Monte Carlo accumulator.\n"); + res = RES_MEM_ERR; + goto error; + } + memset(mc_accums[i], 0, sizeof(struct mc_accum)*nwavelengths); + + res = ssp_rng_proxy_create_rng(rng_proxy, i, rngs + i); + if(res != RES_OK) { + log_error(dev, "Couldn't create the RNG.\n"); + goto error; + } + res = s3d_shape_create_mesh(dev->s3d[i], shapes + i); + if(res != RES_OK) { + log_error(dev, "Couldn't create the Star-3D shape.\n"); + goto error; + } + res = s3d_scene_create(dev->s3d[i], scenes + i); + if(res != RES_OK) { + log_error(dev, "Couldn't create the Star-3D scene.\n"); + goto error; + } + res = s3d_scene_attach_shape(scenes[i], shapes[i]); + if(res != RES_OK) { + log_error(dev, + "Couldn't attach the Star-3D Schiff shape to the Star-3D Schiff scene.\n"); + goto error; + } + } - /* Clear the estimator accumulators */ - memset(darray_mcaccum_data_get(&estimator->accums), 0, - sizeof(struct mc_accum)*nwavelengths); + /* Clear the accumulators */ + memset(estimator->accums, 0, sizeof(struct mc_accum)*nwavelengths); /* Setup and sort the wavelengths */ - FOR_EACH(i, 0, nwavelengths) { - darray_double_data_get(&estimator->wavelengths)[i] = wavelengths[i]; - } - qsort(darray_double_data_get(&estimator->wavelengths), nwavelengths, - sizeof(double), cmp_double); - - FOR_EACH(i, 0, ngeoms) { - struct sschiff_material_properties* props = darray_mtl_data_get(&mtls); - const double* wlengths = darray_double_cdata_get(&estimator->wavelengths); - struct mc_accum* mc_accums = darray_mcaccum_data_get(&estimator->accums); - struct accum* accs = darray_accum_data_get(&accums); + FOR_EACH(i, 0, nwavelengths) estimator->wavelengths[i] = wavelengths[i]; + qsort(estimator->wavelengths, nwavelengths, sizeof(double), cmp_double); + + /* Paralell Schiff integration */ + #pragma omp parallel for schedule(dynamic) + for(i=0; i< ngeoms; ++i) { + const double* wlengths = estimator->wavelengths; struct sschiff_material material = SSCHIFF_NULL_MATERIAL; size_t iwavelength; + const int ithread = omp_get_thread_num(); + res_T res_local; + + if(ATOMIC_GET(&res) != RES_OK) continue; /* Sample a geometry, i.e. a shape and its associated material */ - res = distrib->sample(rng, &material, shape, distrib->context); - if(res != RES_OK) { + res_local = distrib->sample + (rngs[ithread], &material, shapes[ithread], distrib->context); + if(res_local != RES_OK) { log_error(dev, "Error in sampling a Schiff geometry.\n"); - goto error; + ATOMIC_SET(&res, &res_local); + continue; } /* Fetch the per wavelength material properties */ FOR_EACH(iwavelength, 0, nwavelengths) { - material.get_property - (material.material, wavelengths[iwavelength], props + iwavelength); + material.get_property(material.material, wavelengths[iwavelength], + mtls[ithread] + iwavelength); } /* Build the Star-3D representation of the sampled shape */ - S3D(scene_begin_session(scene, S3D_TRACE)); + S3D(scene_begin_session(scenes[ithread], S3D_TRACE)); /* Schiff Estimation */ - res = radiative_properties(dev, rng, (int)i, wlengths, nwavelengths, ndirs, - scene, props, mc_accums, accs); - if(res != RES_OK) goto error; + res_local = radiative_properties(dev, rngs[ithread], (int)i, wlengths, + nwavelengths, ndirs, scenes[ithread], mtls[ithread], mc_accums[ithread], + accums[ithread]); + if(res != RES_OK) ATOMIC_SET(&res, &res_local); - S3D(scene_end_session(scene)); + S3D(scene_end_session(scenes[ithread])); + } + if(res != RES_OK) goto error; /* Handle integration error */ + + /* Merge the per thread integration ressults */ + FOR_EACH(i, 0, dev->nthreads) { + size_t iwlen; + FOR_EACH(iwlen, 0, nwavelengths) { + size_t idata; + FOR_EACH(idata, 0, SSCHIFF_DATA_COUNT__) { + estimator->accums[iwlen].mc_data[idata].weight += + mc_accums[i][iwlen].mc_data[idata].weight; + estimator->accums[iwlen].mc_data[idata].sqr_weight += + mc_accums[i][iwlen].mc_data[idata].sqr_weight; + } + } } exit: - darray_mtl_release(&mtls); - darray_accum_release(&accums); + if(rng_proxy) SSP(rng_proxy_ref_put(rng_proxy)); + /* Release per thread data */ + if(mtls) { + FOR_EACH(i, 0, dev->nthreads) if(mtls[i]) sa_release(mtls[i]); + sa_release(mtls); + } + if(accums) { + FOR_EACH(i, 0, dev->nthreads) if(accums[i]) sa_release(accums[i]); + sa_release(accums); + } + if(mc_accums) { + FOR_EACH(i, 0, dev->nthreads) if(mc_accums[i]) sa_release(mc_accums[i]); + sa_release(mc_accums); + } + if(rngs) { + FOR_EACH(i, 0, dev->nthreads) if(rngs[i]) SSP(rng_ref_put(rngs[i])); + sa_release(rngs); + } + if(shapes) { + FOR_EACH(i, 0, dev->nthreads) if(shapes[i]) S3D(shape_ref_put(shapes[i])); + sa_release(shapes); + } + if(scenes) { + FOR_EACH(i, 0, dev->nthreads) if(scenes[i]) S3D(scene_ref_put(scenes[i])); + sa_release(scenes); + } if(out_estimator) *out_estimator = estimator; - if(shape) S3D(shape_ref_put(shape)); - if(scene) S3D(scene_ref_put(scene)); return res; error: if(estimator) { @@ -702,7 +786,7 @@ sschiff_estimator_get_wavelengths_count (const struct sschiff_estimator* estimator, size_t* count) { if(!estimator || !count) return RES_BAD_ARG; - *count = darray_double_size_get(&estimator->wavelengths); + *count = sa_size(estimator->wavelengths); return RES_OK; } @@ -731,14 +815,14 @@ sschiff_estimator_get_wavelength_state if(!estimator || !state) return RES_BAD_ARG; - wavelengths = darray_double_cdata_get(&estimator->wavelengths); - nwavelengths = darray_double_size_get(&estimator->wavelengths); + wavelengths = estimator->wavelengths; + nwavelengths = sa_size(estimator->wavelengths); find = bsearch (&wavelength, wavelengths, nwavelengths, sizeof(double), cmp_double); if(!find) return RES_BAD_ARG; iwavelength = (size_t)(find - wavelengths); - accum = darray_mcaccum_cdata_get(&estimator->accums) + iwavelength; + accum = estimator->accums + iwavelength; FOR_EACH(i, 0, SSCHIFF_DATA_COUNT__) { get_mc_value(accum->mc_data+i, estimator->nrealisations, state->values+i); @@ -759,9 +843,9 @@ sschiff_estimator_get_states int i; if(!estimator || !states) return RES_BAD_ARG; - nwavelengths = darray_double_size_get(&estimator->wavelengths); - wavelengths = darray_double_cdata_get(&estimator->wavelengths); - accums = darray_mcaccum_cdata_get(&estimator->accums); + nwavelengths = sa_size(estimator->wavelengths); + wavelengths = estimator->wavelengths; + accums = estimator->accums; FOR_EACH(iwlen, 0, nwavelengths) { states[iwlen].wavelength = wavelengths[iwlen]; diff --git a/src/test_sschiff_device.c b/src/test_sschiff_device.c @@ -34,6 +34,7 @@ #include <rsys/rsys.h> #include <star/s3d.h> +#define N SSCHIFF_NTHREADS_DEFAULT static void log_stream(const char* msg, void* ctx) @@ -52,8 +53,8 @@ main(int argc, char** argv) struct s3d_device* s3d; (void)argc, (void)argv; - CHECK(sschiff_device_create(NULL, NULL, 0, NULL, NULL), RES_BAD_ARG); - CHECK(sschiff_device_create(NULL, NULL, 0, NULL, &dev), RES_OK); + CHECK(sschiff_device_create(NULL, NULL, N, 0, NULL, NULL), RES_BAD_ARG); + CHECK(sschiff_device_create(NULL, NULL, N, 0, NULL, &dev), RES_OK); CHECK(sschiff_device_ref_get(NULL), RES_BAD_ARG); CHECK(sschiff_device_ref_get(dev), RES_OK); @@ -64,8 +65,8 @@ main(int argc, char** argv) mem_init_proxy_allocator(&allocator, &mem_default_allocator); CHECK(MEM_ALLOCATED_SIZE(&allocator), 0); - CHECK(sschiff_device_create(NULL, &allocator, 1, NULL, NULL), RES_BAD_ARG); - CHECK(sschiff_device_create(NULL, &allocator, 1, NULL, &dev), RES_OK); + CHECK(sschiff_device_create(NULL, &allocator, N, 1, NULL, NULL), RES_BAD_ARG); + CHECK(sschiff_device_create(NULL, &allocator, N, 1, NULL, &dev), RES_OK); CHECK(sschiff_device_ref_put(dev), RES_OK); CHECK(MEM_ALLOCATED_SIZE(&allocator), 0); @@ -74,21 +75,25 @@ main(int argc, char** argv) logger_set_stream(&logger, LOG_ERROR, log_stream, NULL); logger_set_stream(&logger, LOG_WARNING, log_stream, NULL); - CHECK(sschiff_device_create(&logger, NULL, 0, NULL, NULL), RES_BAD_ARG); - CHECK(sschiff_device_create(&logger, NULL, 0, NULL, &dev), RES_OK); + CHECK(sschiff_device_create(&logger, NULL, N, 0, NULL, NULL), RES_BAD_ARG); + CHECK(sschiff_device_create(&logger, NULL, N, 0, NULL, &dev), RES_OK); CHECK(sschiff_device_ref_put(dev), RES_OK); - CHECK(sschiff_device_create(&logger, &allocator, 1, NULL, NULL), RES_BAD_ARG); - CHECK(sschiff_device_create(&logger, &allocator, 1, NULL, &dev), RES_OK); + CHECK(sschiff_device_create(&logger, &allocator, N, 1, NULL, NULL), RES_BAD_ARG); + CHECK(sschiff_device_create(&logger, &allocator, N, 1, NULL, &dev), RES_OK); CHECK(sschiff_device_ref_put(dev), RES_OK); CHECK(s3d_device_create(NULL, NULL, 0, &s3d), RES_OK); - CHECK(sschiff_device_create(NULL, NULL, 0, s3d, NULL), RES_BAD_ARG); - CHECK(sschiff_device_create(NULL, NULL, 0, s3d, &dev), RES_OK); + CHECK(sschiff_device_create(NULL, NULL, N, 0, s3d, NULL), RES_BAD_ARG); + CHECK(sschiff_device_create(NULL, NULL, N, 0, s3d, &dev), RES_OK); CHECK(s3d_device_ref_put(s3d), RES_OK); CHECK(sschiff_device_ref_put(dev), RES_OK); + CHECK(sschiff_device_create(NULL, NULL, 0, 0, NULL, &dev), RES_BAD_ARG); + CHECK(sschiff_device_create(NULL, NULL, 1, 0, NULL, &dev), RES_OK); + CHECK(sschiff_device_ref_put(dev), RES_OK); + logger_release(&logger); check_memory_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator); diff --git a/src/test_sschiff_estimator_cylinder.c b/src/test_sschiff_estimator_cylinder.c @@ -568,7 +568,8 @@ main(int argc, char** argv) mem_init_proxy_allocator(&allocator, &mem_default_allocator); CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK); - CHECK(sschiff_device_create(NULL, &allocator, 0, NULL, &dev), RES_OK); + CHECK(sschiff_device_create + (NULL, &allocator, SSCHIFF_NTHREADS_DEFAULT, 0, NULL, &dev), RES_OK); cylinder_init(&sampler_ctx.geometry, 64); diff --git a/src/test_sschiff_estimator_sphere.c b/src/test_sschiff_estimator_sphere.c @@ -350,7 +350,8 @@ main(int argc, char** argv) mem_init_proxy_allocator(&allocator, &mem_default_allocator); CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK); - CHECK(sschiff_device_create(NULL, &allocator, 0, NULL, &dev), RES_OK); + CHECK(sschiff_device_create + (NULL, &allocator, SSCHIFF_NTHREADS_DEFAULT, 0, NULL, &dev), RES_OK); sphere_init(&sampler_ctx.geometry, 64);