htrdr

Solving radiative transfer in heterogeneous media
git clone git://git.meso-star.fr/htrdr.git
Log | Files | Refs | README | LICENSE

commit d1befaf9fd97cb5756d697b742eb4ac7735b828d
parent 57e9f9c44675f70d190ea4eeb44bd4de749c5b73
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Mon, 22 Feb 2021 10:37:36 +0100

Fix MPI execution

Output buffer is not allocated on non master process while the
htrdr_draw_map function queried it to retrieve image layout leading to
assertion/invalid memory read.

This commit adds to the htrdr_draw_map_args data structure the
'buffer_layout' member variable defining the layout of the output image
in all situations (i.e. for master and non master processes). It also
updates the htrdr_buffer_create signature that now takes a
htrdr_buffer_layout input argument rather than a set of separated
variables that actually defines this layout.

Diffstat:
Msrc/atmosphere/htrdr_atmosphere.c | 27+++++++++++++++------------
Msrc/atmosphere/htrdr_atmosphere_c.h | 5++++-
Msrc/atmosphere/htrdr_atmosphere_draw_map.c | 2++
Msrc/core/htrdr_buffer.c | 62++++++++++++--------------------------------------------------
Msrc/core/htrdr_buffer.h | 32+++++++++++++++++++++++++++-----
Msrc/core/htrdr_draw_map.c | 70++++++++++++++++++++++++++++++++++++++++++++++------------------------
Msrc/core/htrdr_draw_map.h | 10+++++-----
7 files changed, 111 insertions(+), 97 deletions(-)

diff --git a/src/atmosphere/htrdr_atmosphere.c b/src/atmosphere/htrdr_atmosphere.c @@ -389,21 +389,24 @@ htrdr_atmosphere_create if(res != RES_OK) goto error; } - /* Create the image buffer only on the master process; the image parts - * rendered by the processes are gathered onto the master process. */ - if(!cmd->dump_volumetric_acceleration_structure - && htrdr_get_mpi_rank(htrdr) == 0) { + + if(!cmd->dump_volumetric_acceleration_structure) { struct atmosphere_pixel_format pixfmt = ATMOSPHERE_PIXEL_FORMAT_NULL; atmosphere_get_pixel_format(cmd, &pixfmt); - res = htrdr_buffer_create(htrdr, - args->image.definition[0], /* Width */ - args->image.definition[1], /* Height */ - args->image.definition[0] * pixfmt.size, /* Pitch */ - pixfmt.size, /* Size of a pixel */ - pixfmt.alignment, /* Alignment of a pixel */ - &cmd->buf); - if(res != RES_OK) goto error; + /* Setup the buffer layout */ + cmd->buf_layout.width = args->image.definition[0]; + cmd->buf_layout.height = args->image.definition[1]; + cmd->buf_layout.pitch = args->image.definition[0] * pixfmt.size; + cmd->buf_layout.elmt_size = pixfmt.size; + cmd->buf_layout.alignment = pixfmt.alignment; + + /* Create the image buffer only on the master process; the image parts + * rendered by the others processes are gathered onto the master process */ + if(htrdr_get_mpi_rank(htrdr) == 0) { + res = htrdr_buffer_create(htrdr, &cmd->buf_layout, &cmd->buf); + if(res != RES_OK) goto error; + } } exit: diff --git a/src/atmosphere/htrdr_atmosphere_c.h b/src/atmosphere/htrdr_atmosphere_c.h @@ -19,6 +19,7 @@ #define HTRDR_ATMOSPHERE_C_H #include "core/htrdr_accum.h" +#include "core/htrdr_buffer.h" #include "core/htrdr_sensor.h" #include "core/htrdr_spectral.h" @@ -99,7 +100,9 @@ struct htrdr_atmosphere { struct htrdr_ran_wlen* ran_wlen; struct htrdr_sensor sensor; - struct htrdr_buffer* buf; + + struct htrdr_buffer_layout buf_layout; + struct htrdr_buffer* buf; /* NULL on non master processes */ struct htsky* sky; const char* sky_mtl_name; diff --git a/src/atmosphere/htrdr_atmosphere_draw_map.c b/src/atmosphere/htrdr_atmosphere_draw_map.c @@ -435,6 +435,7 @@ setup_draw_map_args_rectangle ASSERT(cmd && cmd->sensor.type == HTRDR_SENSOR_RECTANGLE && args); *args = HTRDR_DRAW_MAP_ARGS_NULL; args->draw_pixel = draw_pixel_flux; + args->buffer_layout = cmd->buf_layout; args->spp = cmd->spp; args->context = cmd; } @@ -447,6 +448,7 @@ setup_draw_map_args_camera ASSERT(cmd && cmd->sensor.type == HTRDR_SENSOR_CAMERA && args); *args = HTRDR_DRAW_MAP_ARGS_NULL; + args->buffer_layout = cmd->buf_layout; args->spp = cmd->spp; args->context = cmd; diff --git a/src/core/htrdr_buffer.c b/src/core/htrdr_buffer.c @@ -24,14 +24,9 @@ #include <rsys/ref_count.h> struct htrdr_buffer { + struct htrdr_buffer_layout layout; char* mem; - size_t width; - size_t height; - size_t pitch; - size_t elmtsz; - size_t align; - struct htrdr* htrdr; ref_T ref; }; @@ -58,42 +53,16 @@ buffer_release(ref_T* ref) res_T htrdr_buffer_create (struct htrdr* htrdr, - const size_t width, - const size_t height, - const size_t pitch, - const size_t elmtsz, - const size_t align, + const struct htrdr_buffer_layout* layout, struct htrdr_buffer** out_buf) { struct htrdr_buffer* buf = NULL; size_t memsz = 0; res_T res = RES_OK; - ASSERT(htrdr && out_buf); + ASSERT(htrdr && layout && out_buf); - if(!width || !height) { - htrdr_log_err(htrdr, "invalid buffer definition %lux%lu.\n", - (unsigned long)width, (unsigned long)height); - res = RES_BAD_ARG; - goto error; - } - if(pitch < width*elmtsz) { - htrdr_log_err(htrdr, - "invalid buffer pitch `%lu' wrt the buffer width `%lu'. " - "The buffer pitch cannot be less than the buffer width.\n", - (unsigned long)pitch, (unsigned long)width); - res = RES_BAD_ARG; - goto error; - } - if(!elmtsz) { - htrdr_log_err(htrdr, - "the size of the buffer's elements cannot be null.\n"); - res = RES_BAD_ARG; - goto error; - } - if(!IS_POW2(align)) { - htrdr_log_err(htrdr, - "invalid buffer alignment `%lu'. It must be a power of 2.\n", - (unsigned long)align); + if(!htrdr_buffer_layout_check(layout)) { + htrdr_log_err(htrdr, "Invalid buffer memory layout.\n"); res = RES_BAD_ARG; goto error; } @@ -104,16 +73,13 @@ htrdr_buffer_create goto error; } ref_init(&buf->ref); - buf->width = width; - buf->height = height; - buf->pitch = pitch; - buf->elmtsz = elmtsz; - buf->align = align; + buf->layout = *layout; htrdr_ref_get(htrdr); buf->htrdr = htrdr; - memsz = buf->pitch * buf->height; - buf->mem = MEM_ALLOC_ALIGNED(htrdr_get_allocator(htrdr), memsz, align); + memsz = buf->layout.pitch * buf->layout.height; + buf->mem = MEM_ALLOC_ALIGNED + (htrdr_get_allocator(htrdr), memsz, buf->layout.alignment); if(!buf->mem) { res = RES_MEM_ERR; goto error; @@ -150,11 +116,7 @@ htrdr_buffer_get_layout struct htrdr_buffer_layout* layout) { ASSERT(buf && layout); - layout->width = buf->width; - layout->height = buf->height; - layout->pitch = buf->pitch; - layout->elmt_size = buf->elmtsz; - layout->alignment = buf->align; + *layout = buf->layout; } void* @@ -167,7 +129,7 @@ htrdr_buffer_get_data(struct htrdr_buffer* buf) void* htrdr_buffer_at(struct htrdr_buffer* buf, const size_t x, const size_t y) { - ASSERT(buf && x < buf->width && y < buf->height); - return buf->mem + y*buf->pitch + x*buf->elmtsz; + ASSERT(buf && x < buf->layout.width && y < buf->layout.height); + return buf->mem + y*buf->layout.pitch + x*buf->layout.elmt_size; } diff --git a/src/core/htrdr_buffer.h b/src/core/htrdr_buffer.h @@ -19,6 +19,8 @@ #define HTRDR_BUFFER_H #include "core/htrdr.h" + +#include <rsys/math.h> #include <rsys/rsys.h> /* @@ -36,6 +38,30 @@ struct htrdr_buffer_layout { static const struct htrdr_buffer_layout HTRDR_BUFFER_LAYOUT_NULL = HTRDR_BUFFER_LAYOUT_NULL__; +static INLINE int +htrdr_buffer_layout_eq + (const struct htrdr_buffer_layout* a, + const struct htrdr_buffer_layout* b) +{ + ASSERT(a && b); + return a->width == b->width + && a->height == b->height + && a->pitch == b->pitch + && a->elmt_size == b->elmt_size + && a->alignment == b->alignment; +} + +static INLINE int +htrdr_buffer_layout_check(const struct htrdr_buffer_layout* layout) +{ + return layout + && layout->width + && layout->height + && layout->elmt_size + && layout->width*layout->elmt_size <= layout->pitch + && IS_POW2(layout->alignment); +} + /* Forward declarations */ struct htrdr; struct htrdr_buffer; @@ -45,11 +71,7 @@ BEGIN_DECLS HTRDR_CORE_API res_T htrdr_buffer_create (struct htrdr* htrdr, - const size_t width, - const size_t height, - const size_t pitch, /* #Bytes between 2 consecutive line */ - const size_t elmt_size, /* Size of an element in the buffer */ - const size_t alignment, /* Alignement of the buffer */ + const struct htrdr_buffer_layout* layout, struct htrdr_buffer** buf); HTRDR_CORE_API void diff --git a/src/core/htrdr_draw_map.c b/src/core/htrdr_draw_map.c @@ -56,7 +56,7 @@ struct tile { size_t pixal; /* Pixel alignment */ uint16_t x, y; /* 2D coordinates of the tile in tile space */ /* Simulate the flexible array member of the C99 standard */ - char ALIGN(16) pixels[1/*Dummy element*/]; + char ALIGN(16) pixels[1/*Dummy element*/]; } data; }; @@ -73,7 +73,10 @@ struct proc_work { static INLINE int check_draw_map_args(const struct htrdr_draw_map_args* args) { - return args && args->draw_pixel && args->spp; + return args + && args->draw_pixel + && args->spp + && htrdr_buffer_layout_check(&args->buffer_layout); } static INLINE void @@ -125,7 +128,7 @@ tile_create exit: return tile; error: - if(tile) { + if(tile) { tile_ref_put(tile); tile = NULL; } @@ -396,25 +399,24 @@ mpi_steal_work static res_T mpi_gather_tiles (struct htrdr* htrdr, + const struct htrdr_buffer_layout* buf_layout, struct htrdr_buffer* buf, const size_t ntiles, struct list_node* tiles) { /* Compute the size of the tile_data */ - struct htrdr_buffer_layout layout = HTRDR_BUFFER_LAYOUT_NULL; size_t msg_sz = 0; struct list_node* node = NULL; struct tile* tile = NULL; res_T res = RES_OK; - ASSERT(htrdr && tiles); + ASSERT(htrdr && tiles && htrdr_buffer_layout_check(buf_layout)); ASSERT(htrdr->mpi_rank != 0 || buf); (void)ntiles; /* Compute the size of the tile data */ - htrdr_buffer_get_layout(buf, &layout); - msg_sz = - sizeof(struct tile_data) - + TILE_SIZE*TILE_SIZE*layout.elmt_size + msg_sz = + sizeof(struct tile_data) + + TILE_SIZE*TILE_SIZE*buf_layout->elmt_size - 1/* Dummy octet of the flexible array */; ASSERT(msg_sz <= INT_MAX); @@ -427,6 +429,16 @@ mpi_gather_tiles } } else { /* Master process */ size_t itile = 0; + ASSERT(buf); + +#ifndef NDEBUG + { + /* Check data consistency */ + struct htrdr_buffer_layout layout = HTRDR_BUFFER_LAYOUT_NULL; + htrdr_buffer_get_layout(buf, &layout); + ASSERT(htrdr_buffer_layout_eq(&layout, buf_layout)); + } +#endif LIST_FOR_EACH(node, tiles) { struct tile* t = CONTAINER_OF(node, struct tile, node); @@ -439,7 +451,10 @@ mpi_gather_tiles /* Create a temporary tile to receive the tile data computed by the * concurrent MPI processes */ - tile = tile_create(htrdr->allocator, layout.elmt_size, layout.alignment); + tile = tile_create + (htrdr->allocator, + buf_layout->elmt_size, + buf_layout->alignment); if(!tile) { res = RES_MEM_ERR; htrdr_log_err(htrdr, @@ -521,7 +536,6 @@ static res_T draw_map (struct htrdr* htrdr, const struct htrdr_draw_map_args* args, - const struct htrdr_buffer_layout* buf_layout, const size_t ntiles_x, const size_t ntiles_y, const size_t ntiles_adjusted, @@ -535,7 +549,7 @@ draw_map size_t proc_ntiles = 0; ATOMIC nsolved_tiles = 0; ATOMIC res = RES_OK; - ASSERT(htrdr && check_draw_map_args(args) && buf_layout && work && tiles); + ASSERT(htrdr && check_draw_map_args(args) && work && tiles); ASSERT(ntiles_x && ntiles_y && ntiles_adjusted >= ntiles_x*ntiles_y); ASSERT(pix_sz && pix_sz[0] > 0 && pix_sz[1] > 0); (void)ntiles_x, (void)ntiles_y; @@ -589,7 +603,9 @@ draw_map /* Create the tile */ tile = tile_create - (htrdr->allocator, buf_layout->elmt_size, buf_layout->alignment); + (htrdr->allocator, + args->buffer_layout.elmt_size, + args->buffer_layout.alignment); if(!tile) { ATOMIC_SET(&res, RES_MEM_ERR); htrdr_log_err(htrdr, @@ -611,8 +627,8 @@ draw_map tile_org[1] = (uint16_t)(tile_org[1] * TILE_SIZE); /* Compute the size of the tile clamped by the borders of the buffer */ - tile_sz[0] = MMIN(TILE_SIZE, buf_layout->width - tile_org[0]); - tile_sz[1] = MMIN(TILE_SIZE, buf_layout->height - tile_org[1]); + tile_sz[0] = MMIN(TILE_SIZE, args->buffer_layout.width - tile_org[0]); + tile_sz[1] = MMIN(TILE_SIZE, args->buffer_layout.height - tile_org[1]); /* Create a proxy RNG for the current tile. This proxy is used for the * current thread only and thus it has to manage only one RNG. This proxy @@ -691,7 +707,6 @@ htrdr_draw_map size_t ntiles_x, ntiles_y, ntiles, ntiles_adjusted; size_t itile; struct proc_work work; - struct htrdr_buffer_layout layout = HTRDR_BUFFER_LAYOUT_NULL; size_t proc_ntiles_adjusted; double pix_sz[2]; @@ -700,19 +715,26 @@ htrdr_draw_map ASSERT(htrdr && check_draw_map_args(args)); ASSERT(htrdr->mpi_rank != 0 || buf); - htrdr_buffer_get_layout(buf, &layout); +#ifndef NDEBUG + if(htrdr_get_mpi_rank(htrdr) == 0) { + /* Check data consistency */ + struct htrdr_buffer_layout layout = HTRDR_BUFFER_LAYOUT_NULL; + htrdr_buffer_get_layout(buf, &layout); + ASSERT(htrdr_buffer_layout_eq(&layout, &args->buffer_layout)); + } +#endif list_init(&tiles); proc_work_init(htrdr->allocator, &work); /* Compute the overall number of tiles */ - ntiles_x = (layout.width + (TILE_SIZE-1)/*ceil*/)/TILE_SIZE; - ntiles_y = (layout.height+ (TILE_SIZE-1)/*ceil*/)/TILE_SIZE; + ntiles_x = (args->buffer_layout.width + (TILE_SIZE-1)/*ceil*/)/TILE_SIZE; + ntiles_y = (args->buffer_layout.height+ (TILE_SIZE-1)/*ceil*/)/TILE_SIZE; ntiles = ntiles_x * ntiles_y; /* Compute the pixel size in the normalized image plane */ - pix_sz[0] = 1.0 / (double)layout.width; - pix_sz[1] = 1.0 / (double)layout.height; + pix_sz[0] = 1.0 / (double)args->buffer_layout.width; + pix_sz[1] = 1.0 / (double)args->buffer_layout.height; /* Adjust the #tiles for the morton-encoding procedure */ ntiles_adjusted = round_up_pow2(MMAX(ntiles_x, ntiles_y)); @@ -751,7 +773,7 @@ htrdr_draw_map #pragma omp section { - draw_map(htrdr, args, &layout, ntiles_x, ntiles_y, ntiles_adjusted, pix_sz, &work, + draw_map(htrdr, args, ntiles_x, ntiles_y, ntiles_adjusted, pix_sz, &work, &tiles); /* The processes have no more work to do. Stop probing for thieves */ ATOMIC_SET(&probe_thieves, 0); @@ -767,9 +789,9 @@ htrdr_draw_map time_dump(&t0, TIME_ALL, NULL, strbuf, sizeof(strbuf)); htrdr_log(htrdr, "Rendering time: %s\n", strbuf); - /* Gather accum buffers from the group of processes */ + /* Gather tiles to master process */ time_current(&t0); - res = mpi_gather_tiles(htrdr, buf, ntiles, &tiles); + res = mpi_gather_tiles(htrdr, &args->buffer_layout, buf, ntiles, &tiles); if(res != RES_OK) goto error; time_sub(&t0, time_current(&t1), &t0); time_dump(&t0, TIME_ALL, NULL, strbuf, sizeof(strbuf)); diff --git a/src/core/htrdr_draw_map.h b/src/core/htrdr_draw_map.h @@ -19,6 +19,8 @@ #define HTRDR_DRAW_MAP_H #include "core/htrdr.h" +#include "core/htrdr_buffer.h" + #include <rsys/rsys.h> struct htrdr_draw_pixel_args { @@ -49,6 +51,7 @@ typedef void struct htrdr_draw_map_args { htrdr_draw_pixel_T draw_pixel; + struct htrdr_buffer_layout buffer_layout; struct ssp_rng* rng; size_t spp; /* Samples per pixel */ void* context; /* User defined data */ @@ -56,6 +59,7 @@ struct htrdr_draw_map_args { #define HTRDR_DRAW_MAP_ARGS_NULL__ { \ NULL, /* Draw pixel functor */ \ + HTRDR_BUFFER_LAYOUT_NULL__, /* Layout of the destination buffer */ \ NULL, /* Random Number Generator */ \ 0, /* #Samples per pixel */ \ NULL /* User defined data */ \ @@ -63,10 +67,6 @@ struct htrdr_draw_map_args { static const struct htrdr_draw_map_args HTRDR_DRAW_MAP_ARGS_NULL = HTRDR_DRAW_MAP_ARGS_NULL__; -/* Forward declarations */ -struct htrdr; -struct htrdr_buffer; - static INLINE int htrdr_draw_pixel_args_check(const struct htrdr_draw_pixel_args* args) { @@ -86,7 +86,7 @@ HTRDR_CORE_API res_T htrdr_draw_map (struct htrdr* htrdr, const struct htrdr_draw_map_args* args, - struct htrdr_buffer* buf); + struct htrdr_buffer* buf); /* May be NULL for non master processes */ END_DECLS