/*******************************************************************************
* This file is part of SWIFT.
* Copyright (c) 2013 Pedro Gonnet (pedro.gonnet@durham.ac.uk)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*
******************************************************************************/
/* Config parameters. */
#include
/* Some standard headers. */
#include
#include
#include
#include
#include
#include
#include
/* MPI headers. */
#ifdef WITH_MPI
#include
#endif
/* This object's header. */
#include "proxy.h"
/* Local headers. */
#include "cell.h"
#include "engine.h"
#include "error.h"
#include "memuse.h"
#include "space.h"
#include "threadpool.h"
#ifdef WITH_MPI
/* MPI data type for the communications */
MPI_Datatype pcell_mpi_type;
#endif
struct tag_mapper_data {
int *tags_out, *tags_in;
int *offset_out, *offset_in;
struct cell *space_cells;
};
#ifdef WITH_MPI
void proxy_tags_exchange_pack_mapper(void *map_data, int num_elements,
void *extra_data) {
struct cell *cells = (struct cell *)map_data;
struct tag_mapper_data *data = (struct tag_mapper_data *)extra_data;
int *restrict tags_out = data->tags_out;
const int *restrict offset_out = data->offset_out;
struct cell *space_cells = data->space_cells;
const size_t delta = cells - space_cells;
for (int k = 0; k < num_elements; k++) {
if (cells[k].mpi.sendto) {
cell_pack_tags(&cells[k], &tags_out[offset_out[k + delta]]);
}
}
}
void proxy_tags_exchange_unpack_mapper(void *map_data, int num_elements,
void *extra_data) {
int *restrict cids_in = (int *)map_data;
struct tag_mapper_data *data = (struct tag_mapper_data *)extra_data;
const int *restrict offset_in = data->offset_in;
int *restrict tags_in = data->tags_in;
struct cell *space_cells = data->space_cells;
for (int k = 0; k < num_elements; k++) {
const int cid = cids_in[k];
cell_unpack_tags(&tags_in[offset_in[cid]], &space_cells[cid]);
}
}
#endif
/**
* @brief Exchange tags between nodes.
*
* Note that this function assumes that the cell structures have already
* been exchanged, e.g. via #proxy_cells_exchange.
*
* @param proxies The list of #proxy that will send/recv tags
* @param num_proxies The number of proxies.
* @param s The space into which the tags will be unpacked.
*/
void proxy_tags_exchange(struct proxy *proxies, int num_proxies,
struct space *s) {
#ifdef WITH_MPI
/* ticks tic2 = getticks(); */
/* Run through the cells and get the size of the tags that will be sent off.
*/
int count_out = 0;
int *offset_out =
(int *)swift_malloc("tags_offsets_out", s->nr_cells * sizeof(int));
if (offset_out == NULL) error("Error allocating memory for tag offsets");
for (int k = 0; k < s->nr_cells; k++) {
offset_out[k] = count_out;
if (s->cells_top[k].mpi.sendto) {
count_out += s->cells_top[k].mpi.pcell_size;
}
}
/* Run through the proxies and get the count of incoming tags. */
int count_in = 0;
int *offset_in =
(int *)swift_malloc("tags_offsets_in", s->nr_cells * sizeof(int));
if (offset_in == NULL) error("Error allocating memory for tag offsets");
for (int k = 0; k < num_proxies; k++) {
for (int j = 0; j < proxies[k].nr_cells_in; j++) {
offset_in[proxies[k].cells_in[j] - s->cells_top] = count_in;
count_in += proxies[k].cells_in[j]->mpi.pcell_size;
}
}
/* Allocate the tags. */
int *tags_in = NULL;
int *tags_out = NULL;
if (swift_memalign("tags_in", (void **)&tags_in, SWIFT_CACHE_ALIGNMENT,
sizeof(int) * count_in) != 0 ||
swift_memalign("tags_out", (void **)&tags_out, SWIFT_CACHE_ALIGNMENT,
sizeof(int) * count_out) != 0)
error("Failed to allocate tags buffers.");
struct tag_mapper_data extra_data;
extra_data.tags_out = tags_out;
extra_data.offset_out = offset_out;
extra_data.space_cells = s->cells_top;
/* Pack the local tags. */
threadpool_map(&s->e->threadpool, proxy_tags_exchange_pack_mapper,
s->cells_top, s->nr_cells, sizeof(struct cell),
threadpool_auto_chunk_size, &extra_data);
/* if (s->e->verbose) */
/* message("Cell pack tags took %.3f %s.", */
/* clocks_from_ticks(getticks() - tic2), clocks_getunit()); */
/* tic2 = getticks(); */
/* Allocate the incoming and outgoing request handles. */
int num_reqs_out = 0;
int num_reqs_in = 0;
for (int k = 0; k < num_proxies; k++) {
num_reqs_in += proxies[k].nr_cells_in;
num_reqs_out += proxies[k].nr_cells_out;
}
MPI_Request *reqs_in = NULL;
int *cids_in = NULL;
if ((reqs_in = (MPI_Request *)malloc(sizeof(MPI_Request) *
(num_reqs_in + num_reqs_out))) == NULL ||
(cids_in = (int *)malloc(sizeof(int) * (num_reqs_in + num_reqs_out))) ==
NULL)
error("Failed to allocate MPI_Request arrays.");
MPI_Request *reqs_out = &reqs_in[num_reqs_in];
int *cids_out = &cids_in[num_reqs_in];
/* Emit the sends and recvs. */
for (int send_rid = 0, recv_rid = 0, k = 0; k < num_proxies; k++) {
for (int j = 0; j < proxies[k].nr_cells_in; j++) {
const int cid = proxies[k].cells_in[j] - s->cells_top;
cids_in[recv_rid] = cid;
int err = MPI_Irecv(
&tags_in[offset_in[cid]], proxies[k].cells_in[j]->mpi.pcell_size,
MPI_INT, proxies[k].nodeID, cid, MPI_COMM_WORLD, &reqs_in[recv_rid]);
if (err != MPI_SUCCESS) mpi_error(err, "Failed to irecv tags.");
recv_rid += 1;
}
for (int j = 0; j < proxies[k].nr_cells_out; j++) {
const int cid = proxies[k].cells_out[j] - s->cells_top;
cids_out[send_rid] = cid;
int err = MPI_Isend(
&tags_out[offset_out[cid]], proxies[k].cells_out[j]->mpi.pcell_size,
MPI_INT, proxies[k].nodeID, cid, MPI_COMM_WORLD, &reqs_out[send_rid]);
if (err != MPI_SUCCESS) mpi_error(err, "Failed to isend tags.");
send_rid += 1;
}
}
/* if (s->e->verbose) */
/* message("Emitting Send/Recv for tags took %.3f %s.", */
/* clocks_from_ticks(getticks() - tic2), clocks_getunit()); */
/* tic2 = getticks(); */
/* Wait for all the sends to have completed. */
if (MPI_Waitall(num_reqs_in, reqs_in, MPI_STATUSES_IGNORE) != MPI_SUCCESS)
error("MPI_Waitall on sends failed.");
/* if (s->e->verbose) */
/* message("WaitAll on tags took %.3f %s.", */
/* clocks_from_ticks(getticks() - tic2), clocks_getunit()); */
/* tic2 = getticks(); */
/* Unpack the tags we received */
extra_data.tags_in = tags_in;
extra_data.offset_in = offset_in;
extra_data.space_cells = s->cells_top;
threadpool_map(&s->e->threadpool, proxy_tags_exchange_unpack_mapper, cids_in,
num_reqs_in, sizeof(int), threadpool_auto_chunk_size,
&extra_data);
/* if (s->e->verbose) */
/* message("Cell unpack tags took %.3f %s.", */
/* clocks_from_ticks(getticks() - tic2), clocks_getunit()); */
/* Wait for all the sends to have completed. */
if (MPI_Waitall(num_reqs_out, reqs_out, MPI_STATUSES_IGNORE) != MPI_SUCCESS)
error("MPI_Waitall on sends failed.");
/* Clean up. */
swift_free("tags_in", tags_in);
swift_free("tags_out", tags_out);
swift_free("tags_offsets_in", offset_in);
swift_free("tags_offsets_out", offset_out);
free(reqs_in);
free(cids_in);
#else
error("SWIFT was not compiled with MPI support.");
#endif
}
/**
* @brief Exchange extra information about the grid construction between nodes.
*
* Note that this function assumes that the cell structures have already
* been exchanged, e.g. via #proxy_cells_exchange.
*
* @param proxies The list of #proxy that will send/recv tags
* @param num_proxies The number of proxies.
* @param s The space into which the tags will be unpacked.
*/
void proxy_grid_extra_exchange(struct proxy *proxies, int num_proxies,
struct space *s) {
#ifdef WITH_MPI
ticks tic2 = getticks();
/* Run through the cells and get the size of the info that will be sent off.
*/
int count_out = 0;
int *offset_out =
(int *)swift_malloc("info_offsets_out", s->nr_cells * sizeof(int));
if (offset_out == NULL) error("Error allocating memory for info offsets");
for (int k = 0; k < s->nr_cells; k++) {
offset_out[k] = count_out;
if (s->cells_top[k].mpi.sendto) {
count_out += s->cells_top[k].mpi.pcell_size;
}
}
/* Run through the proxies and get the count of incoming info. */
int count_in = 0;
int *offset_in =
(int *)swift_malloc("info_offsets_in", s->nr_cells * sizeof(int));
if (offset_in == NULL) error("Error allocating memory for info offsets");
for (int k = 0; k < num_proxies; k++) {
for (int j = 0; j < proxies[k].nr_cells_in; j++) {
offset_in[proxies[k].cells_in[j] - s->cells_top] = count_in;
count_in += proxies[k].cells_in[j]->mpi.pcell_size;
}
}
/* Allocate the tags. */
enum grid_construction_level *extra_info_in = NULL;
enum grid_construction_level *extra_info_out = NULL;
if (swift_memalign("extra_info_in", (void **)&extra_info_in,
SWIFT_CACHE_ALIGNMENT,
sizeof(enum grid_construction_level) * count_in) != 0 ||
swift_memalign("extra_info_out", (void **)&extra_info_out,
SWIFT_CACHE_ALIGNMENT,
sizeof(enum grid_construction_level) * count_out) != 0)
error("Failed to allocate extra info buffers.");
/* Pack the local grid info. */
for (int k = 0; k < s->nr_cells; k++) {
if (s->cells_top[k].mpi.sendto) {
cell_pack_grid_extra(&s->cells_top[k], &extra_info_out[offset_out[k]]);
}
}
if (s->e->verbose)
message("Cell pack grid extra took %.3f %s.",
clocks_from_ticks(getticks() - tic2), clocks_getunit());
/* Allocate the incoming and outgoing request handles. */
int num_reqs_out = 0;
int num_reqs_in = 0;
for (int k = 0; k < num_proxies; k++) {
num_reqs_in += proxies[k].nr_cells_in;
num_reqs_out += proxies[k].nr_cells_out;
}
MPI_Request *reqs_in = NULL;
int *cids_in = NULL;
if ((reqs_in = (MPI_Request *)malloc(sizeof(MPI_Request) *
(num_reqs_in + num_reqs_out))) == NULL ||
(cids_in = (int *)malloc(sizeof(int) * (num_reqs_in + num_reqs_out))) ==
NULL)
error("Failed to allocate MPI_Request arrays.");
MPI_Request *reqs_out = &reqs_in[num_reqs_in];
int *cids_out = &cids_in[num_reqs_in];
/* Emit the sends and recvs. */
for (int send_rid = 0, recv_rid = 0, k = 0; k < num_proxies; k++) {
for (int j = 0; j < proxies[k].nr_cells_in; j++) {
const int cid = proxies[k].cells_in[j] - s->cells_top;
cids_in[recv_rid] = cid;
int err =
MPI_Irecv(&extra_info_in[offset_in[cid]],
proxies[k].cells_in[j]->mpi.pcell_size, MPI_INT,
proxies[k].nodeID, cid, MPI_COMM_WORLD, &reqs_in[recv_rid]);
if (err != MPI_SUCCESS) mpi_error(err, "Failed to irecv grid info.");
recv_rid += 1;
}
for (int j = 0; j < proxies[k].nr_cells_out; j++) {
const int cid = proxies[k].cells_out[j] - s->cells_top;
cids_out[send_rid] = cid;
int err = MPI_Isend(&extra_info_out[offset_out[cid]],
proxies[k].cells_out[j]->mpi.pcell_size, MPI_INT,
proxies[k].nodeID, cid, MPI_COMM_WORLD,
&reqs_out[send_rid]);
if (err != MPI_SUCCESS) mpi_error(err, "Failed to isend grid info.");
send_rid += 1;
}
}
tic2 = getticks();
/* Wait for each recv and unpack the grid info into the local cells. */
for (int k = 0; k < num_reqs_in; k++) {
int pid = MPI_UNDEFINED;
MPI_Status status;
if (MPI_Waitany(num_reqs_in, reqs_in, &pid, &status) != MPI_SUCCESS ||
pid == MPI_UNDEFINED)
error("MPI_Waitany failed.");
const int cid = cids_in[pid];
cell_unpack_grid_extra(&extra_info_in[offset_in[cid]], &s->cells_top[cid],
NULL);
}
if (s->e->verbose)
message("Cell unpack grid extra took %.3f %s.",
clocks_from_ticks(getticks() - tic2), clocks_getunit());
/* Wait for all the sends to have completed. */
if (MPI_Waitall(num_reqs_out, reqs_out, MPI_STATUSES_IGNORE) != MPI_SUCCESS)
error("MPI_Waitall on sends failed.");
/* Clean up. */
swift_free("extra_info_in", extra_info_in);
swift_free("extra_info_out", extra_info_out);
swift_free("info_offsets_in", offset_in);
swift_free("info_offsets_out", offset_out);
free(reqs_in);
free(cids_in);
#else
error("SWIFT was not compiled with MPI support.");
#endif
}
/**
* @brief Exchange cells with a remote node, first part.
*
* The first part of the transaction sends the local cell count and the packed
* #pcell array to the destination node, and enqueues an @c MPI_Irecv for
* the foreign cell counts.
*
* @param p The #proxy.
*/
void proxy_cells_exchange_first(struct proxy *p) {
#ifdef WITH_MPI
/* Get the number of pcells we will need to send. */
p->size_pcells_out = 0;
for (int k = 0; k < p->nr_cells_out; k++)
p->size_pcells_out += p->cells_out[k]->mpi.pcell_size;
/* Send the number of pcells. */
int err = MPI_Isend(&p->size_pcells_out, 1, MPI_INT, p->nodeID,
p->mynodeID * proxy_tag_shift + proxy_tag_count,
MPI_COMM_WORLD, &p->req_cells_count_out);
if (err != MPI_SUCCESS) mpi_error(err, "Failed to isend nr of pcells.");
// message( "isent pcell count (%i) from node %i to node %i." ,
// p->size_pcells_out , p->mynodeID , p->nodeID ); fflush(stdout);
/* Allocate and fill the pcell buffer. */
if (p->pcells_out != NULL) swift_free("pcells_out", p->pcells_out);
if (swift_memalign("pcells_out", (void **)&p->pcells_out,
SWIFT_STRUCT_ALIGNMENT,
sizeof(struct pcell) * p->size_pcells_out) != 0)
error("Failed to allocate pcell_out buffer.");
for (int ind = 0, k = 0; k < p->nr_cells_out; k++) {
memcpy(&p->pcells_out[ind], p->cells_out[k]->mpi.pcell,
sizeof(struct pcell) * p->cells_out[k]->mpi.pcell_size);
ind += p->cells_out[k]->mpi.pcell_size;
}
/* Send the pcell buffer. */
err = MPI_Isend(p->pcells_out, p->size_pcells_out, pcell_mpi_type, p->nodeID,
p->mynodeID * proxy_tag_shift + proxy_tag_cells,
MPI_COMM_WORLD, &p->req_cells_out);
if (err != MPI_SUCCESS) mpi_error(err, "Failed to pcell_out buffer.");
// message( "isent pcells (%i) from node %i to node %i." , p->size_pcells_out
// , p->mynodeID , p->nodeID ); fflush(stdout);
/* Receive the number of pcells. */
err = MPI_Irecv(&p->size_pcells_in, 1, MPI_INT, p->nodeID,
p->nodeID * proxy_tag_shift + proxy_tag_count, MPI_COMM_WORLD,
&p->req_cells_count_in);
if (err != MPI_SUCCESS) mpi_error(err, "Failed to irecv nr of pcells.");
// message( "irecv pcells count on node %i from node %i." , p->mynodeID ,
// p->nodeID ); fflush(stdout);
#else
error("SWIFT was not compiled with MPI support.");
#endif
}
/**
* @brief Exchange cells with a remote node, second part.
*
* Once the incomming cell count has been received, allocate a buffer
* for the foreign packed #pcell array and emit the @c MPI_Irecv for
* it.
*
* @param p The #proxy.
*/
void proxy_cells_exchange_second(struct proxy *p) {
#ifdef WITH_MPI
/* Re-allocate the pcell_in buffer. */
if (p->pcells_in != NULL) swift_free("pcells_in", p->pcells_in);
if (swift_memalign("pcells_in", (void **)&p->pcells_in,
SWIFT_STRUCT_ALIGNMENT,
sizeof(struct pcell) * p->size_pcells_in) != 0)
error("Failed to allocate pcell_in buffer.");
/* Receive the particle buffers. */
int err = MPI_Irecv(p->pcells_in, p->size_pcells_in, pcell_mpi_type,
p->nodeID, p->nodeID * proxy_tag_shift + proxy_tag_cells,
MPI_COMM_WORLD, &p->req_cells_in);
if (err != MPI_SUCCESS) mpi_error(err, "Failed to irecv part data.");
// message( "irecv pcells (%i) on node %i from node %i." , p->size_pcells_in
// , p->mynodeID , p->nodeID ); fflush(stdout);
#else
error("SWIFT was not compiled with MPI support.");
#endif
}
#ifdef WITH_MPI
void proxy_cells_count_mapper(void *map_data, int num_elements,
void *extra_data) {
struct cell *cells = (struct cell *)map_data;
for (int k = 0; k < num_elements; k++) {
if (cells[k].mpi.sendto)
cells[k].mpi.pcell_size = cell_get_tree_size(&cells[k]);
}
}
struct pack_mapper_data {
struct space *s;
int *offset;
struct pcell *pcells;
int with_gravity;
};
void proxy_cells_pack_mapper(void *map_data, int num_elements,
void *extra_data) {
struct cell *cells = (struct cell *)map_data;
struct pack_mapper_data *data = (struct pack_mapper_data *)extra_data;
for (int k = 0; k < num_elements; k++) {
if (cells[k].mpi.sendto) {
ptrdiff_t ind = &cells[k] - data->s->cells_top;
cells[k].mpi.pcell = &data->pcells[data->offset[ind]];
cell_pack(&cells[k], cells[k].mpi.pcell, data->with_gravity);
}
}
}
void proxy_cells_exchange_first_mapper(void *map_data, int num_elements,
void *extra_data) {
struct proxy *proxies = (struct proxy *)map_data;
for (int k = 0; k < num_elements; k++) {
proxy_cells_exchange_first(&proxies[k]);
}
}
#endif // WITH_MPI
/**
* @brief Exchange the cell structures with all proxies.
*
* @param proxies The list of #proxy that will send/recv cells.
* @param num_proxies The number of proxies.
* @param s The space into which the particles will be unpacked.
* @param with_gravity Are we running with gravity and hence need
* to exchange multipoles?
*/
void proxy_cells_exchange(struct proxy *proxies, int num_proxies,
struct space *s, const int with_gravity) {
#ifdef WITH_MPI
MPI_Request *reqs;
if ((reqs = (MPI_Request *)malloc(sizeof(MPI_Request) * 2 * num_proxies)) ==
NULL)
error("Failed to allocate request buffers.");
MPI_Request *reqs_in = reqs;
MPI_Request *reqs_out = &reqs[num_proxies];
ticks tic2 = getticks();
/* Run through the cells and get the size of the ones that will be sent off.
*/
threadpool_map(&s->e->threadpool, proxy_cells_count_mapper, s->cells_top,
s->nr_cells, sizeof(struct cell), threadpool_auto_chunk_size,
/*extra_data=*/NULL);
int count_out = 0;
int *offset =
(int *)swift_malloc("proxy_cell_offset", s->nr_cells * sizeof(int));
if (offset == NULL) error("Error allocating memory for proxy cell offsets");
for (int k = 0; k < s->nr_cells; k++) {
offset[k] = count_out;
if (s->cells_top[k].mpi.sendto) count_out += s->cells_top[k].mpi.pcell_size;
}
if (s->e->verbose)
message("Counting cells to send took %.3f %s.",
clocks_from_ticks(getticks() - tic2), clocks_getunit());
/* Allocate the pcells. */
struct pcell *pcells = NULL;
if (swift_memalign("pcells", (void **)&pcells, SWIFT_CACHE_ALIGNMENT,
sizeof(struct pcell) * count_out) != 0)
error("Failed to allocate pcell buffer.");
tic2 = getticks();
/* Pack the cells. */
struct pack_mapper_data data = {s, offset, pcells, with_gravity};
threadpool_map(&s->e->threadpool, proxy_cells_pack_mapper, s->cells_top,
s->nr_cells, sizeof(struct cell), threadpool_auto_chunk_size,
&data);
if (s->e->verbose)
message("Packing cells took %.3f %s.", clocks_from_ticks(getticks() - tic2),
clocks_getunit());
/* Launch the first part of the exchange. */
threadpool_map(&s->e->threadpool, proxy_cells_exchange_first_mapper, proxies,
num_proxies, sizeof(struct proxy), threadpool_auto_chunk_size,
/*extra_data=*/NULL);
for (int k = 0; k < num_proxies; k++) {
reqs_in[k] = proxies[k].req_cells_count_in;
reqs_out[k] = proxies[k].req_cells_count_out;
}
/* Wait for each count to come in and start the recv. */
for (int k = 0; k < num_proxies; k++) {
int pid = MPI_UNDEFINED;
MPI_Status status;
if (MPI_Waitany(num_proxies, reqs_in, &pid, &status) != MPI_SUCCESS ||
pid == MPI_UNDEFINED)
error("MPI_Waitany failed.");
// message( "request from proxy %i has arrived." , pid );
proxy_cells_exchange_second(&proxies[pid]);
}
/* Wait for all the sends to have finished too. */
if (MPI_Waitall(num_proxies, reqs_out, MPI_STATUSES_IGNORE) != MPI_SUCCESS)
error("MPI_Waitall on sends failed.");
/* Set the requests for the cells. */
for (int k = 0; k < num_proxies; k++) {
reqs_in[k] = proxies[k].req_cells_in;
reqs_out[k] = proxies[k].req_cells_out;
}
tic2 = getticks();
/* Wait for each pcell array to come in from the proxies. */
for (int k = 0; k < num_proxies; k++) {
int pid = MPI_UNDEFINED;
MPI_Status status;
if (MPI_Waitany(num_proxies, reqs_in, &pid, &status) != MPI_SUCCESS ||
pid == MPI_UNDEFINED)
error("MPI_Waitany failed.");
// message( "cell data from proxy %i has arrived." , pid );
for (int count = 0, j = 0; j < proxies[pid].nr_cells_in; j++)
count += cell_unpack(&proxies[pid].pcells_in[count],
proxies[pid].cells_in[j], s, with_gravity);
}
if (s->e->verbose)
message("Un-packing cells took %.3f %s.",
clocks_from_ticks(getticks() - tic2), clocks_getunit());
/* Wait for all the sends to have finished too. */
if (MPI_Waitall(num_proxies, reqs_out, MPI_STATUSES_IGNORE) != MPI_SUCCESS)
error("MPI_Waitall on sends failed.");
/* Clean up. */
free(reqs);
swift_free("pcells", pcells);
swift_free("proxy_cell_offset", offset);
for (int k = 0; k < num_proxies; k++) {
swift_free("pcells_in", proxies[k].pcells_in);
swift_free("pcells_out", proxies[k].pcells_out);
proxies[k].pcells_in = NULL;
proxies[k].pcells_out = NULL;
}
#else
error("SWIFT was not compiled with MPI support.");
#endif
}
/**
* @brief Add a cell to the given proxy's input list.
*
* @param p The #proxy.
* @param c The #cell.
* @param type Why is this cell in the proxy (hdro, gravity, ...) ?
*/
void proxy_addcell_in(struct proxy *p, struct cell *c, int type) {
if (type == proxy_cell_type_none) error("Invalid type for proxy");
/* Check if the cell is already registered with the proxy. */
for (int k = 0; k < p->nr_cells_in; k++)
if (p->cells_in[k] == c) {
/* Update the type */
p->cells_in_type[k] |= type;
return;
}
/* Do we need to grow the number of in cells? */
if (p->nr_cells_in == p->size_cells_in) {
p->size_cells_in *= proxy_buffgrow;
struct cell **temp_cell;
if ((temp_cell = (struct cell **)swift_malloc(
"cells_in", sizeof(struct cell *) * p->size_cells_in)) == NULL)
error("Failed to allocate incoming cell list.");
memcpy(temp_cell, p->cells_in, sizeof(struct cell *) * p->nr_cells_in);
swift_free("cells_in", p->cells_in);
p->cells_in = temp_cell;
int *temp_type;
if ((temp_type = (int *)swift_malloc(
"cells_in_type", sizeof(int) * p->size_cells_in)) == NULL)
error("Failed to allocate incoming cell type list.");
memcpy(temp_type, p->cells_in_type, sizeof(int) * p->nr_cells_in);
swift_free("cells_in_type", p->cells_in_type);
p->cells_in_type = temp_type;
}
/* Add the cell. */
p->cells_in[p->nr_cells_in] = c;
p->cells_in_type[p->nr_cells_in] = type;
p->nr_cells_in += 1;
}
/**
* @brief Add a cell to the given proxy's output list.
*
* @param p The #proxy.
* @param c The #cell.
* @param type Why is this cell in the proxy (hdro, gravity, ...) ?
*/
void proxy_addcell_out(struct proxy *p, struct cell *c, int type) {
if (type == proxy_cell_type_none) error("Invalid type for proxy");
/* Check if the cell is already registered with the proxy. */
for (int k = 0; k < p->nr_cells_out; k++)
if (p->cells_out[k] == c) {
/* Update the type */
p->cells_out_type[k] |= type;
return;
}
/* Do we need to grow the number of out cells? */
if (p->nr_cells_out == p->size_cells_out) {
p->size_cells_out *= proxy_buffgrow;
struct cell **temp_cell;
if ((temp_cell = (struct cell **)swift_malloc(
"cells_out", sizeof(struct cell *) * p->size_cells_out)) == NULL)
error("Failed to allocate outgoing cell list.");
memcpy(temp_cell, p->cells_out, sizeof(struct cell *) * p->nr_cells_out);
swift_free("cells_out", p->cells_out);
p->cells_out = temp_cell;
int *temp_type;
if ((temp_type = (int *)swift_malloc(
"cells_out_type", sizeof(int) * p->size_cells_out)) == NULL)
error("Failed to allocate outgoing cell type list.");
memcpy(temp_type, p->cells_out_type, sizeof(int) * p->nr_cells_out);
swift_free("cells_out_type", p->cells_out_type);
p->cells_out_type = temp_type;
}
/* Add the cell. */
p->cells_out[p->nr_cells_out] = c;
p->cells_out_type[p->nr_cells_out] = type;
p->nr_cells_out += 1;
}
/**
* @brief Exchange particles with a remote node.
*
* @param p The #proxy.
*/
void proxy_parts_exchange_first(struct proxy *p) {
#ifdef WITH_MPI
/* Send the number of particles. */
p->buff_out[0] = p->nr_parts_out;
p->buff_out[1] = p->nr_gparts_out;
p->buff_out[2] = p->nr_sparts_out;
p->buff_out[3] = p->nr_bparts_out;
p->buff_out[4] = p->nr_sinks_out;
#ifdef SWIFT_DEBUG_CHECKS
message("Number of particles out [%i , %i, %i, %i, %i]", p->nr_parts_out,
p->nr_gparts_out, p->nr_sparts_out, p->nr_bparts_out,
p->nr_sinks_out);
#endif /* SWIFT_DEBUG_CHECKS */
if (MPI_Isend(p->buff_out, PROXY_EXCHANGE_NUMBER_PARTICLE_TYPES, MPI_INT,
p->nodeID, p->mynodeID * proxy_tag_shift + proxy_tag_count,
MPI_COMM_WORLD, &p->req_parts_count_out) != MPI_SUCCESS)
error("Failed to isend nr of parts.");
#ifdef SWIFT_DEBUG_CHECKS
message("isent particle counts [%i, %i, %i, %i, %i] from node %i to node %i.",
p->buff_out[0], p->buff_out[1], p->buff_out[2], p->buff_out[3],
p->buff_out[4], p->mynodeID, p->nodeID);
fflush(stdout);
#endif /* SWIFT_DEBUG_CHECKS */
/* Send the particle buffers. */
if (p->nr_parts_out > 0) {
if (MPI_Isend(p->parts_out, p->nr_parts_out, part_mpi_type, p->nodeID,
p->mynodeID * proxy_tag_shift + proxy_tag_parts,
MPI_COMM_WORLD, &p->req_parts_out) != MPI_SUCCESS ||
MPI_Isend(p->xparts_out, p->nr_parts_out, xpart_mpi_type, p->nodeID,
p->mynodeID * proxy_tag_shift + proxy_tag_xparts,
MPI_COMM_WORLD, &p->req_xparts_out) != MPI_SUCCESS)
error("Failed to isend part data.");
#ifdef SWIFT_DEBUG_CHECKS
message("isent particle data (%i) to node %i.", p->nr_parts_out, p->nodeID);
fflush(stdout);
for (int k = 0; k < p->nr_parts_out; k++)
message("sending particle %lli, x=[%.3e %.3e %.3e], h=%.3e, to node %i.",
p->parts_out[k].id, p->parts_out[k].x[0], p->parts_out[k].x[1],
p->parts_out[k].x[2], p->parts_out[k].h, p->nodeID);
#endif /* SWIFT_DEBUG_CHECKS */
}
if (p->nr_gparts_out > 0) {
if (MPI_Isend(p->gparts_out, p->nr_gparts_out, gpart_mpi_type, p->nodeID,
p->mynodeID * proxy_tag_shift + proxy_tag_gparts,
MPI_COMM_WORLD, &p->req_gparts_out) != MPI_SUCCESS)
error("Failed to isend gpart data.");
#ifdef SWIFT_DEBUG_CHECKS
message("isent gpart data (%i) to node %i.", p->nr_gparts_out, p->nodeID);
fflush(stdout);
for (int k = 0; k < p->nr_parts_out; k++)
message("sending gpart %lli, x=[%.3e %.3e %.3e], to node %i.",
p->gparts_out[k].id_or_neg_offset, p->gparts_out[k].x[0],
p->gparts_out[k].x[1], p->gparts_out[k].x[2], p->nodeID);
#endif /* SWIFT_DEBUG_CHECKS */
}
if (p->nr_sparts_out > 0) {
if (MPI_Isend(p->sparts_out, p->nr_sparts_out, spart_mpi_type, p->nodeID,
p->mynodeID * proxy_tag_shift + proxy_tag_sparts,
MPI_COMM_WORLD, &p->req_sparts_out) != MPI_SUCCESS)
error("Failed to isend spart data.");
#ifdef SWIFT_DEBUG_CHECKS
message("isent spart data (%i) to node %i.", p->nr_sparts_out, p->nodeID);
fflush(stdout);
for (int k = 0; k < p->nr_sparts_out; k++)
message("sending spart %lli, x=[%.3e %.3e %.3e], h=%.3e, to node %i.",
p->sparts_out[k].id, p->sparts_out[k].x[0], p->sparts_out[k].x[1],
p->sparts_out[k].x[2], p->sparts_out[k].h, p->nodeID);
#endif /* SWIFT_DEBUG_CHECKS */
}
if (p->nr_bparts_out > 0) {
if (MPI_Isend(p->bparts_out, p->nr_bparts_out, bpart_mpi_type, p->nodeID,
p->mynodeID * proxy_tag_shift + proxy_tag_bparts,
MPI_COMM_WORLD, &p->req_bparts_out) != MPI_SUCCESS)
error("Failed to isend bpart data.");
#ifdef SWIFT_DEBUG_CHECKS
message("isent bpart data (%i) to node %i.", p->nr_bparts_out, p->nodeID);
fflush(stdout);
for (int k = 0; k < p->nr_bparts_out; k++)
message("sending bpart %lli, x=[%.3e %.3e %.3e], h=%.3e, to node %i.",
p->bparts_out[k].id, p->bparts_out[k].x[0], p->bparts_out[k].x[1],
p->bparts_out[k].x[2], p->bparts_out[k].h, p->nodeID);
#endif /* SWIFT_DEBUG_CHECKS */
}
if (p->nr_sinks_out > 0) {
if (MPI_Isend(p->sinks_out, p->nr_sinks_out, sink_mpi_type, p->nodeID,
p->mynodeID * proxy_tag_shift + proxy_tag_sinks,
MPI_COMM_WORLD, &p->req_sinks_out) != MPI_SUCCESS)
error("Failed to isend sink data.");
#ifdef SWIFT_DEBUG_CHECKS
message("isent sink data (%i) to node %i.", p->nr_sinks_out, p->nodeID);
fflush(stdout);
for (int k = 0; k < p->nr_sinks_out; k++)
message("sending sinks %lli, x=[%.3e %.3e %.3e], h=%.3e, to node %i.",
p->sinks_out[k].id, p->sinks_out[k].x[0], p->sinks_out[k].x[1],
p->sinks_out[k].x[2], p->sinks_out[k].h, p->nodeID);
#endif /* SWIFT_DEBUG_CHECKS */
}
/* Receive the number of particles. */
if (MPI_Irecv(p->buff_in, PROXY_EXCHANGE_NUMBER_PARTICLE_TYPES, MPI_INT,
p->nodeID, p->nodeID * proxy_tag_shift + proxy_tag_count,
MPI_COMM_WORLD, &p->req_parts_count_in) != MPI_SUCCESS)
error("Failed to irecv nr of parts.");
#ifdef SWIFT_DEBUG_CHECKS
message(
"irecv particle counts [%i, %i, %i, %i, %i] from node %i, I am node %i.",
p->buff_in[0], p->buff_in[1], p->buff_in[2], p->buff_in[3], p->buff_in[4],
p->nodeID, p->mynodeID);
fflush(stdout);
#endif /* SWIFT_DEBUG_CHECKS */
#else
error("SWIFT was not compiled with MPI support.");
#endif
}
void proxy_parts_exchange_second(struct proxy *p) {
#ifdef WITH_MPI
/* Unpack the incomming parts counts. */
p->nr_parts_in = p->buff_in[0];
p->nr_gparts_in = p->buff_in[1];
p->nr_sparts_in = p->buff_in[2];
p->nr_bparts_in = p->buff_in[3];
p->nr_sinks_in = p->buff_in[4];
/* Is there enough space in the buffers? */
if (p->nr_parts_in > p->size_parts_in) {
do {
p->size_parts_in *= proxy_buffgrow;
} while (p->nr_parts_in > p->size_parts_in);
swift_free("parts_in", p->parts_in);
swift_free("xparts_in", p->xparts_in);
if ((p->parts_in = (struct part *)swift_malloc(
"parts_in", sizeof(struct part) * p->size_parts_in)) == NULL ||
(p->xparts_in = (struct xpart *)swift_malloc(
"xparts_in", sizeof(struct xpart) * p->size_parts_in)) == NULL)
error("Failed to re-allocate parts_in buffers.");
}
if (p->nr_gparts_in > p->size_gparts_in) {
do {
p->size_gparts_in *= proxy_buffgrow;
} while (p->nr_gparts_in > p->size_gparts_in);
swift_free("gparts_in", p->gparts_in);
if ((p->gparts_in = (struct gpart *)swift_malloc(
"gparts_in", sizeof(struct gpart) * p->size_gparts_in)) == NULL)
error("Failed to re-allocate gparts_in buffers.");
}
if (p->nr_sparts_in > p->size_sparts_in) {
do {
p->size_sparts_in *= proxy_buffgrow;
} while (p->nr_sparts_in > p->size_sparts_in);
swift_free("sparts_in", p->sparts_in);
if ((p->sparts_in = (struct spart *)swift_malloc(
"sparts_in", sizeof(struct spart) * p->size_sparts_in)) == NULL)
error("Failed to re-allocate sparts_in buffers.");
}
if (p->nr_bparts_in > p->size_bparts_in) {
do {
p->size_bparts_in *= proxy_buffgrow;
} while (p->nr_bparts_in > p->size_bparts_in);
swift_free("bparts_in", p->bparts_in);
if ((p->bparts_in = (struct bpart *)swift_malloc(
"bparts_in", sizeof(struct bpart) * p->size_bparts_in)) == NULL)
error("Failed to re-allocate bparts_in buffers.");
}
if (p->nr_sinks_in > p->size_sinks_in) {
do {
p->size_sinks_in *= proxy_buffgrow;
} while (p->nr_sinks_in > p->size_sinks_in);
swift_free("sinks_in", p->sinks_in);
if ((p->sinks_in = (struct sink *)swift_malloc(
"sinks_in", sizeof(struct sink) * p->size_sinks_in)) == NULL)
error("Failed to re-allocate sinks_in buffers.");
}
/* Receive the particle buffers. */
if (p->nr_parts_in > 0) {
if (MPI_Irecv(p->parts_in, p->nr_parts_in, part_mpi_type, p->nodeID,
p->nodeID * proxy_tag_shift + proxy_tag_parts, MPI_COMM_WORLD,
&p->req_parts_in) != MPI_SUCCESS ||
MPI_Irecv(p->xparts_in, p->nr_parts_in, xpart_mpi_type, p->nodeID,
p->nodeID * proxy_tag_shift + proxy_tag_xparts,
MPI_COMM_WORLD, &p->req_xparts_in) != MPI_SUCCESS)
error("Failed to irecv part data.");
#ifdef SWIFT_DEBUG_CHECKS
message("irecv particle data (%i) from node %i.", p->nr_parts_in,
p->nodeID);
fflush(stdout);
for (int k = 0; k < p->nr_parts_in; k++)
message("receiving parts %lli, x=[%.3e %.3e %.3e], h=%.3e, from node %i.",
p->parts_in[k].id, p->parts_in[k].x[0], p->parts_in[k].x[1],
p->parts_in[k].x[2], p->parts_in[k].h, p->nodeID);
#endif /* SWIFT_DEBUG_CHECKS */
}
if (p->nr_gparts_in > 0) {
if (MPI_Irecv(p->gparts_in, p->nr_gparts_in, gpart_mpi_type, p->nodeID,
p->nodeID * proxy_tag_shift + proxy_tag_gparts,
MPI_COMM_WORLD, &p->req_gparts_in) != MPI_SUCCESS)
error("Failed to irecv gpart data.");
#ifdef SWIFT_DEBUG_CHECKS
message("irecv gpart data (%i) from node %i.", p->nr_gparts_in, p->nodeID);
fflush(stdout);
for (int k = 0; k < p->nr_gparts_in; k++)
message("receiving gparts %lli, x=[%.3e %.3e %.3e], from node %i.",
p->gparts_in[k].id_or_neg_offset, p->gparts_in[k].x[0],
p->gparts_in[k].x[1], p->gparts_in[k].x[2], p->nodeID);
#endif /* SWIFT_DEBUG_CHECKS */
}
if (p->nr_sparts_in > 0) {
if (MPI_Irecv(p->sparts_in, p->nr_sparts_in, spart_mpi_type, p->nodeID,
p->nodeID * proxy_tag_shift + proxy_tag_sparts,
MPI_COMM_WORLD, &p->req_sparts_in) != MPI_SUCCESS)
error("Failed to irecv spart data.");
#ifdef SWIFT_DEBUG_CHECKS
message("irecv spart data (%i) from node %i.", p->nr_sparts_in, p->nodeID);
fflush(stdout);
for (int k = 0; k < p->nr_sparts_in; k++)
message(
"receiving sparts %lli, x=[%.3e %.3e %.3e], h=%.3e, from node %i.",
p->sparts_in[k].id, p->sparts_in[k].x[0], p->sparts_in[k].x[1],
p->sparts_in[k].x[2], p->sparts_in[k].h, p->nodeID);
#endif
}
if (p->nr_bparts_in > 0) {
if (MPI_Irecv(p->bparts_in, p->nr_bparts_in, bpart_mpi_type, p->nodeID,
p->nodeID * proxy_tag_shift + proxy_tag_bparts,
MPI_COMM_WORLD, &p->req_bparts_in) != MPI_SUCCESS)
error("Failed to irecv bpart data.");
#ifdef SWIFT_DEBUG_CHECKS
message("irecv bpart data (%i) from node %i.", p->nr_bparts_in, p->nodeID);
fflush(stdout);
for (int k = 0; k < p->nr_bparts_in; k++)
message(
"receiving bparts %lli, x=[%.3e %.3e %.3e], h=%.3e, from node %i.",
p->bparts_in[k].id, p->bparts_in[k].x[0], p->bparts_in[k].x[1],
p->bparts_in[k].x[2], p->bparts_in[k].h, p->nodeID);
#endif /* SWIFT_DEBUG_CHECKS */
}
if (p->nr_sinks_in > 0) {
if (MPI_Irecv(p->sinks_in, p->nr_sinks_in, sink_mpi_type, p->nodeID,
p->nodeID * proxy_tag_shift + proxy_tag_sinks, MPI_COMM_WORLD,
&p->req_sinks_in) != MPI_SUCCESS)
error("Failed to irecv sink data.");
#ifdef SWIFT_DEBUG_CHECKS
message("irecv sink data (%i) from node %i.", p->nr_sinks_in, p->nodeID);
fflush(stdout);
for (int k = 0; k < p->nr_sinks_in; k++)
message("receiving sinks %lli, x=[%.3e %.3e %.3e], h=%.3e, from node %i.",
p->sinks_in[k].id, p->sinks_in[k].x[0], p->sinks_in[k].x[1],
p->sinks_in[k].x[2], p->sinks_in[k].h, p->nodeID);
#endif /* SWIFT_DEBUG_CHECKS */
}
#else
error("SWIFT was not compiled with MPI support.");
#endif
}
/**
* @brief Load parts onto a proxy for exchange.
*
* @param p The #proxy.
* @param parts Pointer to an array of #part to send.
* @param xparts Pointer to an array of #xpart to send.
* @param N The number of parts.
*/
void proxy_parts_load(struct proxy *p, const struct part *parts,
const struct xpart *xparts, int N) {
/* Is there enough space in the buffer? */
if (p->nr_parts_out + N > p->size_parts_out) {
do {
p->size_parts_out *= proxy_buffgrow;
} while (p->nr_parts_out + N > p->size_parts_out);
struct part *tp = NULL;
struct xpart *txp = NULL;
if ((tp = (struct part *)swift_malloc(
"parts_out", sizeof(struct part) * p->size_parts_out)) == NULL ||
(txp = (struct xpart *)swift_malloc(
"xparts_out", sizeof(struct xpart) * p->size_parts_out)) == NULL)
error("Failed to re-allocate parts_out buffers.");
memcpy(tp, p->parts_out, sizeof(struct part) * p->nr_parts_out);
memcpy(txp, p->xparts_out, sizeof(struct xpart) * p->nr_parts_out);
swift_free("parts_out", p->parts_out);
swift_free("xparts_out", p->xparts_out);
p->parts_out = tp;
p->xparts_out = txp;
}
/* Copy the parts and xparts data to the buffer. */
memcpy(&p->parts_out[p->nr_parts_out], parts, sizeof(struct part) * N);
memcpy(&p->xparts_out[p->nr_parts_out], xparts, sizeof(struct xpart) * N);
/* Increase the counters. */
p->nr_parts_out += N;
}
/**
* @brief Load gparts onto a proxy for exchange.
*
* @param p The #proxy.
* @param gparts Pointer to an array of #gpart to send.
* @param N The number of gparts.
*/
void proxy_gparts_load(struct proxy *p, const struct gpart *gparts, int N) {
/* Is there enough space in the buffer? */
if (p->nr_gparts_out + N > p->size_gparts_out) {
do {
p->size_gparts_out *= proxy_buffgrow;
} while (p->nr_gparts_out + N > p->size_gparts_out);
struct gpart *tp;
if ((tp = (struct gpart *)swift_malloc(
"gparts_out", sizeof(struct gpart) * p->size_gparts_out)) == NULL)
error("Failed to re-allocate gparts_out buffers.");
memcpy(tp, p->gparts_out, sizeof(struct gpart) * p->nr_gparts_out);
swift_free("gparts_out", p->gparts_out);
p->gparts_out = tp;
}
/* Copy the parts and xparts data to the buffer. */
memcpy(&p->gparts_out[p->nr_gparts_out], gparts, sizeof(struct gpart) * N);
/* Increase the counters. */
p->nr_gparts_out += N;
}
/**
* @brief Load sparts onto a proxy for exchange.
*
* @param p The #proxy.
* @param sparts Pointer to an array of #spart to send.
* @param N The number of sparts.
*/
void proxy_sparts_load(struct proxy *p, const struct spart *sparts, int N) {
/* Is there enough space in the buffer? */
if (p->nr_sparts_out + N > p->size_sparts_out) {
do {
p->size_sparts_out *= proxy_buffgrow;
} while (p->nr_sparts_out + N > p->size_sparts_out);
struct spart *tp;
if ((tp = (struct spart *)swift_malloc(
"sparts_out", sizeof(struct spart) * p->size_sparts_out)) == NULL)
error("Failed to re-allocate sparts_out buffers.");
memcpy(tp, p->sparts_out, sizeof(struct spart) * p->nr_sparts_out);
swift_free("sparts_out", p->sparts_out);
p->sparts_out = tp;
}
/* Copy the parts and xparts data to the buffer. */
memcpy(&p->sparts_out[p->nr_sparts_out], sparts, sizeof(struct spart) * N);
/* Increase the counters. */
p->nr_sparts_out += N;
}
/**
* @brief Load bparts onto a proxy for exchange.
*
* @param p The #proxy.
* @param bparts Pointer to an array of #bpart to send.
* @param N The number of bparts.
*/
void proxy_bparts_load(struct proxy *p, const struct bpart *bparts, int N) {
/* Is there enough space in the buffer? */
if (p->nr_bparts_out + N > p->size_bparts_out) {
do {
p->size_bparts_out *= proxy_buffgrow;
} while (p->nr_bparts_out + N > p->size_bparts_out);
struct bpart *tp;
if ((tp = (struct bpart *)swift_malloc(
"bparts_out", sizeof(struct bpart) * p->size_bparts_out)) == NULL)
error("Failed to re-allocate bparts_out buffers.");
memcpy(tp, p->bparts_out, sizeof(struct bpart) * p->nr_bparts_out);
swift_free("bparts_out", p->bparts_out);
p->bparts_out = tp;
}
/* Copy the parts and xparts data to the buffer. */
memcpy(&p->bparts_out[p->nr_bparts_out], bparts, sizeof(struct bpart) * N);
/* Increase the counters. */
p->nr_bparts_out += N;
}
/**
* @brief Load sinks onto a proxy for exchange.
*
* @param p The #proxy.
* @param sinks Pointer to an array of #sink to send.
* @param N The number of sinks.
*/
void proxy_sinks_load(struct proxy *p, const struct sink *sinks, int N) {
/* Is there enough space in the buffer? */
if (p->nr_sinks_out + N > p->size_sinks_out) {
do {
p->size_sinks_out *= proxy_buffgrow;
} while (p->nr_sinks_out + N > p->size_sinks_out);
struct sink *tp;
if ((tp = (struct sink *)swift_malloc(
"sinks_out", sizeof(struct sink) * p->size_sinks_out)) == NULL)
error("Failed to re-allocate sinks_out buffers.");
memcpy(tp, p->sinks_out, sizeof(struct sink) * p->nr_sinks_out);
swift_free("sinks_out", p->sinks_out);
p->sinks_out = tp;
}
/* Copy the parts and xparts data to the buffer. */
memcpy(&p->sinks_out[p->nr_sinks_out], sinks, sizeof(struct sink) * N);
/* Increase the counters. */
p->nr_sinks_out += N;
}
/**
* @brief Frees the memory allocated for the particle proxies and sets their
* size back to the initial state.
*
* @param p The #proxy.
*/
void proxy_free_particle_buffers(struct proxy *p) {
if (p->size_parts_out > proxy_buffinit) {
swift_free("parts_out", p->parts_out);
swift_free("xparts_out", p->xparts_out);
p->size_parts_out = proxy_buffinit;
if ((p->parts_out = (struct part *)swift_malloc(
"parts_out", sizeof(struct part) * p->size_parts_out)) == NULL)
error("Failed to allocate parts_out buffers.");
if ((p->xparts_out = (struct xpart *)swift_malloc(
"xparts_out", sizeof(struct xpart) * p->size_parts_out)) == NULL)
error("Failed to allocate xparts_out buffers.");
}
if (p->size_parts_in > proxy_buffinit) {
swift_free("parts_in", p->parts_in);
swift_free("xparts_in", p->xparts_in);
p->size_parts_in = proxy_buffinit;
if ((p->parts_in = (struct part *)swift_malloc(
"parts_in", sizeof(struct part) * p->size_parts_in)) == NULL)
error("Failed to allocate parts_in buffers.");
if ((p->xparts_in = (struct xpart *)swift_malloc(
"xparts_in", sizeof(struct xpart) * p->size_parts_in)) == NULL)
error("Failed to allocate xparts_in buffers.");
}
if (p->size_gparts_out > proxy_buffinit) {
swift_free("gparts_out", p->gparts_out);
p->size_gparts_out = proxy_buffinit;
if ((p->gparts_out = (struct gpart *)swift_malloc(
"gparts_out", sizeof(struct gpart) * p->size_gparts_out)) == NULL)
error("Failed to allocate gparts_out buffers.");
}
if (p->size_gparts_in > proxy_buffinit) {
swift_free("gparts_in", p->gparts_in);
p->size_gparts_in = proxy_buffinit;
if ((p->gparts_in = (struct gpart *)swift_malloc(
"gparts_in", sizeof(struct gpart) * p->size_gparts_in)) == NULL)
error("Failed to allocate gparts_in buffers.");
}
if (p->size_sparts_out > proxy_buffinit) {
swift_free("sparts_out", p->sparts_out);
p->size_sparts_out = proxy_buffinit;
if ((p->sparts_out = (struct spart *)swift_malloc(
"sparts_out", sizeof(struct spart) * p->size_sparts_out)) == NULL)
error("Failed to allocate sparts_out buffers.");
}
if (p->size_sparts_in > proxy_buffinit) {
swift_free("sparts_in", p->sparts_in);
p->size_sparts_in = proxy_buffinit;
if ((p->sparts_in = (struct spart *)swift_malloc(
"sparts_in", sizeof(struct spart) * p->size_sparts_in)) == NULL)
error("Failed to allocate sparts_in buffers.");
}
if (p->size_bparts_out > proxy_buffinit) {
swift_free("bparts_out", p->bparts_out);
p->size_bparts_out = proxy_buffinit;
if ((p->bparts_out = (struct bpart *)swift_malloc(
"bparts_out", sizeof(struct bpart) * p->size_bparts_out)) == NULL)
error("Failed to allocate bparts_out buffers.");
}
if (p->size_bparts_in > proxy_buffinit) {
swift_free("bparts_in", p->bparts_in);
p->size_bparts_in = proxy_buffinit;
if ((p->bparts_in = (struct bpart *)swift_malloc(
"bparts_in", sizeof(struct bpart) * p->size_bparts_in)) == NULL)
error("Failed to allocate bparts_in buffers.");
}
if (p->size_sinks_out > proxy_buffinit) {
swift_free("sinks_out", p->sinks_out);
p->size_sinks_out = proxy_buffinit;
if ((p->sinks_out = (struct sink *)swift_malloc(
"sinks_out", sizeof(struct sink) * p->size_sinks_out)) == NULL)
error("Failed to allocate sinks_out buffers.");
}
if (p->size_sinks_in > proxy_buffinit) {
swift_free("sinks_in", p->sinks_in);
p->size_sinks_in = proxy_buffinit;
if ((p->sinks_in = (struct sink *)swift_malloc(
"sinks_in", sizeof(struct sink) * p->size_sinks_in)) == NULL)
error("Failed to allocate sinks_in buffers.");
}
}
/**
* @brief Initialize the given proxy.
*
* @param p The #proxy.
* @param mynodeID The node this proxy is running on.
* @param nodeID The node with which this proxy will communicate.
*/
void proxy_init(struct proxy *p, int mynodeID, int nodeID) {
/* Set the nodeID. */
p->mynodeID = mynodeID;
p->nodeID = nodeID;
/* Allocate the cell send and receive buffers, if needed. */
if (p->cells_in == NULL) {
p->size_cells_in = proxy_buffinit;
if ((p->cells_in = (struct cell **)swift_malloc(
"cells_in", sizeof(void *) * p->size_cells_in)) == NULL)
error("Failed to allocate cells_in buffer.");
if ((p->cells_in_type = (int *)swift_malloc(
"cells_in_type", sizeof(int) * p->size_cells_in)) == NULL)
error("Failed to allocate cells_in_type buffer.");
}
p->nr_cells_in = 0;
if (p->cells_out == NULL) {
p->size_cells_out = proxy_buffinit;
if ((p->cells_out = (struct cell **)swift_malloc(
"cells_out", sizeof(void *) * p->size_cells_out)) == NULL)
error("Failed to allocate cells_out buffer.");
if ((p->cells_out_type = (int *)swift_malloc(
"cells_out_type", sizeof(int) * p->size_cells_out)) == NULL)
error("Failed to allocate cells_out_type buffer.");
}
p->nr_cells_out = 0;
/* Allocate the part send and receive buffers, if needed. */
if (p->parts_in == NULL) {
p->size_parts_in = proxy_buffinit;
if ((p->parts_in = (struct part *)swift_malloc(
"parts_in", sizeof(struct part) * p->size_parts_in)) == NULL ||
(p->xparts_in = (struct xpart *)swift_malloc(
"xparts_in", sizeof(struct xpart) * p->size_parts_in)) == NULL)
error("Failed to allocate parts_in buffers.");
}
p->nr_parts_in = 0;
if (p->parts_out == NULL) {
p->size_parts_out = proxy_buffinit;
if ((p->parts_out = (struct part *)swift_malloc(
"parts_out", sizeof(struct part) * p->size_parts_out)) == NULL ||
(p->xparts_out = (struct xpart *)swift_malloc(
"xparts_out", sizeof(struct xpart) * p->size_parts_out)) == NULL)
error("Failed to allocate parts_out buffers.");
}
p->nr_parts_out = 0;
/* Allocate the gpart send and receive buffers, if needed. */
if (p->gparts_in == NULL) {
p->size_gparts_in = proxy_buffinit;
if ((p->gparts_in = (struct gpart *)swift_malloc(
"gparts_in", sizeof(struct gpart) * p->size_gparts_in)) == NULL)
error("Failed to allocate gparts_in buffers.");
}
p->nr_gparts_in = 0;
if (p->gparts_out == NULL) {
p->size_gparts_out = proxy_buffinit;
if ((p->gparts_out = (struct gpart *)swift_malloc(
"gparts_out", sizeof(struct gpart) * p->size_gparts_out)) == NULL)
error("Failed to allocate gparts_out buffers.");
}
p->nr_gparts_out = 0;
/* Allocate the spart send and receive buffers, if needed. */
if (p->sparts_in == NULL) {
p->size_sparts_in = proxy_buffinit;
if ((p->sparts_in = (struct spart *)swift_malloc(
"sparts_in", sizeof(struct spart) * p->size_sparts_in)) == NULL)
error("Failed to allocate sparts_in buffers.");
}
p->nr_sparts_in = 0;
if (p->sparts_out == NULL) {
p->size_sparts_out = proxy_buffinit;
if ((p->sparts_out = (struct spart *)swift_malloc(
"sparts_out", sizeof(struct spart) * p->size_sparts_out)) == NULL)
error("Failed to allocate sparts_out buffers.");
}
p->nr_sparts_out = 0;
/* Allocate the bpart send and receive buffers, if needed. */
if (p->bparts_in == NULL) {
p->size_bparts_in = proxy_buffinit;
if ((p->bparts_in = (struct bpart *)swift_malloc(
"bparts_in", sizeof(struct bpart) * p->size_bparts_in)) == NULL)
error("Failed to allocate bparts_in buffers.");
}
p->nr_bparts_in = 0;
if (p->bparts_out == NULL) {
p->size_bparts_out = proxy_buffinit;
if ((p->bparts_out = (struct bpart *)swift_malloc(
"bparts_out", sizeof(struct bpart) * p->size_bparts_out)) == NULL)
error("Failed to allocate bparts_out buffers.");
}
p->nr_bparts_out = 0;
/* Allocate the sinks send and receive buffers, if needed. */
if (p->sinks_in == NULL) {
p->size_sinks_in = proxy_buffinit;
if ((p->sinks_in = (struct sink *)swift_malloc(
"sinks_in", sizeof(struct sink) * p->size_sinks_in)) == NULL)
error("Failed to allocate sinks_in buffers.");
}
p->nr_sinks_in = 0;
if (p->sinks_out == NULL) {
p->size_sinks_out = proxy_buffinit;
if ((p->sinks_out = (struct sink *)swift_malloc(
"sinks_out", sizeof(struct sink) * p->size_sinks_out)) == NULL)
error("Failed to allocate sinks_out buffers.");
}
p->nr_sinks_out = 0;
}
/**
* @brief Free the memory allocated by a #proxy
*/
void proxy_clean(struct proxy *p) {
swift_free("cells_in", p->cells_in);
swift_free("cells_out", p->cells_out);
swift_free("cells_in_type", p->cells_in_type);
swift_free("cells_out_type", p->cells_out_type);
swift_free("pcells_in", p->pcells_in);
swift_free("pcells_out", p->pcells_out);
swift_free("parts_out", p->parts_out);
swift_free("xparts_out", p->xparts_out);
swift_free("gparts_out", p->gparts_out);
swift_free("sparts_out", p->sparts_out);
swift_free("bparts_out", p->bparts_out);
swift_free("sinks_out", p->sinks_out);
swift_free("parts_in", p->parts_in);
swift_free("xparts_in", p->xparts_in);
swift_free("gparts_in", p->gparts_in);
swift_free("sparts_in", p->sparts_in);
swift_free("bparts_in", p->bparts_in);
swift_free("sinks_in", p->sinks_in);
}
/**
* @brief Registers the MPI types for the proxy cells.
*/
void proxy_create_mpi_type(void) {
#ifdef WITH_MPI
if (MPI_Type_contiguous(sizeof(struct pcell) / sizeof(unsigned char),
MPI_BYTE, &pcell_mpi_type) != MPI_SUCCESS ||
MPI_Type_commit(&pcell_mpi_type) != MPI_SUCCESS) {
error("Failed to create MPI type for parts.");
}
#else
error("SWIFT was not compiled with MPI support.");
#endif
}
void proxy_free_mpi_type(void) {
#ifdef WITH_MPI
MPI_Type_free(&pcell_mpi_type);
#else
error("SWIFT was not compiled with MPI support.");
#endif
}