[SCM] Gerris Flow Solver branch, upstream, updated. e8f73a07832050124d2b8bf6c6f35b33180e65a8
Stephane Popinet
popinet at users.sf.net
Tue Nov 24 12:24:31 UTC 2009
The following commit has been merged in the upstream branch:
commit d330d3a8fc88cd7ed6705b52007b5fb42b671136
Author: Stephane Popinet <popinet at users.sf.net>
Date: Tue Jul 14 11:36:51 2009 +1000
Dynamic parallel load-balancing (EventBalance)
darcs-hash:20090714013651-d4795-aedb8a52b8a2c1f3410412501146adfc23a8bcbd.gz
diff --git a/src/Makefile.am b/src/Makefile.am
index 9c21263..6b0aa37 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -58,6 +58,7 @@ GFS_HDS = \
map.h \
river.h \
moving.h \
+ balance.h \
version.h
pkginclude_HEADERS = \
@@ -102,6 +103,7 @@ SRC = \
map.c \
river.c \
moving.c \
+ balance.c \
$(GFS_HDS)
domain.c: version.h
diff --git a/src/balance.c b/src/balance.c
new file mode 100644
index 0000000..81274ad
--- /dev/null
+++ b/src/balance.c
@@ -0,0 +1,300 @@
+/* Gerris - The GNU Flow Solver
+ * Copyright (C) 2001-2009 National Institute of Water and Atmospheric Research
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 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 General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "balance.h"
+#include "mpi_boundary.h"
+#include "adaptive.h"
+
+/* GfsEventBalance: Object */
+
+#ifdef HAVE_MPI
+
+static void find_neighbors (GfsBox * box, GArray * pe)
+{
+ FttDirection d;
+ for (d = 0; d < FTT_NEIGHBORS; d++)
+ if (GFS_IS_BOUNDARY_MPI (box->neighbor[d])) {
+ guint process = GFS_BOUNDARY_MPI (box->neighbor[d])->process;
+ gboolean found = FALSE;
+ gint i;
+ for (i = 0; i < pe->len && !found; i++)
+ if (g_array_index (pe, guint, i) == process)
+ found = TRUE;
+ if (!found)
+ g_array_append_val (pe, process);
+ }
+}
+
+static GArray * neighboring_processors (GfsDomain * domain)
+{
+ GArray * pe = g_array_new (FALSE, FALSE, sizeof (guint));
+ if (domain->pid >= 0)
+ gts_container_foreach (GTS_CONTAINER (domain), (GtsFunc) find_neighbors, pe);
+ return pe;
+}
+
+static void count (FttCell * cell, int * n)
+{
+ (*n)++;
+}
+
+#define NITERMAX 100
+#define TOL 0.001
+
+typedef struct {
+ guint * pid; /* pid of neighbors */
+ gdouble * flow; /* flow to neighbors */
+ guint n; /* number of neighbors */
+} BalancingFlow;
+
+/*
+ * Computes the "balancing flow" necessary to balance the domain
+ * sizes on all the processes. @average is the average domain size
+ * (i.e. the target domain size).
+ */
+static BalancingFlow * balancing_flow_new (GfsDomain * domain, int average)
+{
+ BalancingFlow * b;
+
+ b = g_malloc0 (sizeof (BalancingFlow));
+ GArray * pe = neighboring_processors (domain);
+ if (pe->len == 0) {
+ g_array_free (pe, TRUE);
+ return b;
+ }
+ int size = 0, i;
+ gfs_domain_traverse_leaves (domain, (FttCellTraverseFunc) count, &size);
+ gdouble rsize = size - average;
+ gdouble * lambda = g_malloc (sizeof (gdouble)*(pe->len + 1)), lambda1, eps = G_MAXDOUBLE;
+ MPI_Request * request = g_malloc (sizeof (MPI_Request)*pe->len);
+ lambda1 = 0.;
+ /* this is Gamma and s from the "double-loop" fix of Johnson,
+ Bickson and Dolev, 2009, equation (6) */
+ gdouble Gamma = 0.5*pe->len, s = 0.5;
+ gdouble tolerance = MAX (TOL*average, 1.);
+ int niter = NITERMAX;
+ while (niter-- && eps > tolerance) {
+ MPI_Status status;
+ /* Send lambda to all neighbors */
+ lambda[0] = lambda1;
+ for (i = 0; i < pe->len; i++)
+ MPI_Isend (&(lambda[0]), 1, MPI_DOUBLE, g_array_index (pe, guint , i),
+ domain->pid,
+ MPI_COMM_WORLD,
+ &(request[i]));
+ /* Do one iteration of the "double-loop"-fixed Jacobi method for
+ the (graph)-Poisson equation */
+ gdouble rhs = rsize;
+ for (i = 0; i < pe->len; i++) {
+ MPI_Recv (&(lambda[i + 1]), 1, MPI_DOUBLE, g_array_index (pe, guint , i),
+ g_array_index (pe, guint , i),
+ MPI_COMM_WORLD, &status);
+ rhs += lambda[i + 1];
+ }
+ /* update RHS and lambda for "double-loop"-fix */
+ rsize = (1. - s)*rsize + s*(size - average + Gamma*lambda[0]);
+ lambda1 = rhs/(Gamma + pe->len);
+ eps = fabs (lambda[0] - lambda1);
+ /* synchronize */
+ for (i = 0; i < pe->len; i++)
+ MPI_Wait (&request[i], &status);
+ gfs_all_reduce (domain, eps, MPI_DOUBLE, MPI_MAX);
+ }
+ g_free (request);
+ if (niter < 0 && domain->pid == 0)
+ g_warning ("balancing_flow(): could not converge after %d iterations", NITERMAX);
+
+ b->n = pe->len;
+ lambda1 = lambda[0];
+ for (i = 0; i < b->n; i++)
+ lambda[i] = lambda1 - lambda[i + 1];
+ b->flow = lambda;
+ b->pid = (guint *) g_array_free (pe, FALSE);
+ return b;
+}
+
+static void balancing_flow_destroy (BalancingFlow * b)
+{
+ g_free (b->pid);
+ g_free (b->flow);
+ g_free (b);
+}
+
+typedef struct {
+ GfsBox * box;
+ gint dest, n, min, neighboring;
+} BoxData;
+
+static void select_neighbouring_box (GfsBox * box, BoxData * b)
+{
+ gint neighboring = 0;
+ FttDirection d;
+
+ for (d = 0; d < FTT_NEIGHBORS; d++)
+ if (GFS_IS_BOUNDARY_MPI (box->neighbor[d]) &&
+ GFS_BOUNDARY_MPI (box->neighbor[d])->process == b->dest)
+ neighboring++;
+
+ if (neighboring && neighboring >= b->neighboring) {
+ box->size = 0;
+ ftt_cell_traverse (box->root, FTT_PRE_ORDER, FTT_TRAVERSE_LEAFS, -1,
+ (FttCellTraverseFunc) count, &(box->size));
+ if (neighboring > b->neighboring ||
+ fabs (box->size - b->n) < fabs (b->box->size - b->n)) {
+ b->box = box;
+ b->neighboring = neighboring;
+ }
+ }
+}
+
+static void get_pid (GfsBox * box, guint * pid)
+{
+ pid[box->id - 1] = gfs_box_domain (box)->pid;
+}
+
+static void update_box_pid (GfsBox * box, guint * pid)
+{
+ FttDirection d;
+ for (d = 0; d < FTT_NEIGHBORS; d++)
+ if (GFS_IS_BOUNDARY_MPI (box->neighbor[d]))
+ GFS_BOUNDARY_MPI (box->neighbor[d])->process =
+ pid[GFS_BOUNDARY_MPI (box->neighbor[d])->id - 1];
+}
+
+#endif /* HAVE_MPI */
+
+static void gfs_event_balance_write (GtsObject * o, FILE * fp)
+{
+ GfsEventBalance * s = GFS_EVENT_BALANCE (o);
+
+ if (GTS_OBJECT_CLASS (gfs_event_balance_class ())->parent_class->write)
+ (* GTS_OBJECT_CLASS (gfs_event_balance_class ())->parent_class->write)
+ (o, fp);
+
+ fprintf (fp, " %g", s->max);
+}
+
+static void gfs_event_balance_read (GtsObject ** o, GtsFile * fp)
+{
+ GfsEventBalance * s = GFS_EVENT_BALANCE (*o);
+ GfsDomain * domain = GFS_DOMAIN (gfs_object_simulation (s));
+
+ if (GTS_OBJECT_CLASS (gfs_event_balance_class ())->parent_class->read)
+ (* GTS_OBJECT_CLASS (gfs_event_balance_class ())->parent_class->read)
+ (o, fp);
+ if (fp->type == GTS_ERROR)
+ return;
+
+ s->max = gfs_read_constant (fp, domain);
+}
+
+static gboolean gfs_event_balance_event (GfsEvent * event, GfsSimulation * sim)
+{
+ if ((* GFS_EVENT_CLASS (GTS_OBJECT_CLASS (gfs_event_balance_class ())->parent_class)->event)
+ (event, sim)) {
+ GfsDomain * domain = GFS_DOMAIN (sim);
+ GfsEventBalance * s = GFS_EVENT_BALANCE (event);
+ GtsRange size, boundary, mpiwait;
+
+ gfs_domain_stats_balance (domain, &size, &boundary, &mpiwait);
+ if (size.max/size.min > 1. + s->max) {
+#ifdef HAVE_MPI
+ BalancingFlow * balance = balancing_flow_new (domain, size.mean);
+ GPtrArray * request = g_ptr_array_new ();
+ int modified = FALSE;
+ int i;
+ /* Send boxes */
+ for (i = 0; i < balance->n; i++)
+ if (balance->flow[i] > 0.) { /* largest subdomain */
+ GSList * l = NULL;
+ if (gts_container_size (GTS_CONTAINER (domain)) > 1) {
+ BoxData b;
+ b.box = NULL; b.neighboring = 0; b.n = balance->flow[i];
+ b.dest = balance->pid[i];
+ /* we need to find the list of boxes which minimizes
+ |\sum n_i - n| where n_i is the size of box i. This is known in
+ combinatorial optimisation as a "knapsack problem". */
+ gts_container_foreach (GTS_CONTAINER (domain), (GtsFunc) select_neighbouring_box, &b);
+ if (b.box && b.box->size <= 2*b.n) {
+ l = g_slist_prepend (l, b.box);
+ modified = TRUE;
+ }
+ }
+ g_ptr_array_add (request, gfs_send_boxes (domain, l, balance->pid[i]));
+ g_slist_free (l);
+ }
+ /* Receive boxes */
+ for (i = 0; i < balance->n; i++)
+ if (balance->flow[i] < 0.) /* smallest subdomain */
+ g_slist_free (gfs_receive_boxes (domain, balance->pid[i]));
+ /* Synchronize */
+ for (i = 0; i < request->len; i++)
+ gfs_wait (g_ptr_array_index (request, i));
+ g_ptr_array_free (request, TRUE);
+ balancing_flow_destroy (balance);
+ /* Reshape */
+ gfs_all_reduce (domain, modified, MPI_INT, MPI_MAX);
+ if (modified) {
+ /* Updates the pid associated with each box */
+ guint nb = gts_container_size (GTS_CONTAINER (domain));
+ gfs_all_reduce (domain, nb, MPI_UNSIGNED, MPI_SUM);
+ guint * pid = g_malloc0 (sizeof (guint)*nb);
+ gts_container_foreach (GTS_CONTAINER (domain), (GtsFunc) get_pid, pid);
+ MPI_Allreduce (pid, pid, nb, MPI_UNSIGNED, MPI_MAX, MPI_COMM_WORLD);
+ /* pid[id] now contains the current pid of box with index id */
+ gts_container_foreach (GTS_CONTAINER (domain), (GtsFunc) update_box_pid, pid);
+ g_free (pid);
+ gfs_domain_reshape (domain, gfs_domain_depth (domain));
+ }
+#else /* not HAVE_MPI */
+ g_assert_not_reached ();
+#endif /* not HAVE_MPI */
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void gfs_event_balance_class_init (GfsEventClass * klass)
+{
+ GTS_OBJECT_CLASS (klass)->read = gfs_event_balance_read;
+ GTS_OBJECT_CLASS (klass)->write = gfs_event_balance_write;
+ GFS_EVENT_CLASS (klass)->event = gfs_event_balance_event;
+}
+
+GfsEventClass * gfs_event_balance_class (void)
+{
+ static GfsEventClass * klass = NULL;
+
+ if (klass == NULL) {
+ GtsObjectClassInfo gfs_event_balance_info = {
+ "GfsEventBalance",
+ sizeof (GfsEventBalance),
+ sizeof (GfsEventClass),
+ (GtsObjectClassInitFunc) gfs_event_balance_class_init,
+ (GtsObjectInitFunc) NULL,
+ (GtsArgSetFunc) NULL,
+ (GtsArgGetFunc) NULL
+ };
+ klass = gts_object_class_new (GTS_OBJECT_CLASS (gfs_event_class ()),
+ &gfs_event_balance_info);
+ }
+
+ return klass;
+}
diff --git a/src/init.h b/src/balance.h
similarity index 58%
copy from src/init.h
copy to src/balance.h
index 425b2a2..2f5281f 100644
--- a/src/init.h
+++ b/src/balance.h
@@ -1,5 +1,5 @@
/* Gerris - The GNU Flow Solver
- * Copyright (C) 2001 National Institute of Water and Atmospheric Research
+ * Copyright (C) 2001-2009 National Institute of Water and Atmospheric Research
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -17,21 +17,35 @@
* 02111-1307, USA.
*/
-#ifndef __INIT_H__
-#define __INIT_H__
-
-#include <gts.h>
+#ifndef __BALANCE_H__
+#define __BALANCE_H__
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
-GtsObjectClass ** gfs_classes (void);
-void gfs_init (int * argc,
- char *** argv);
+#include "event.h"
+
+/* GfsEventBalance: Header */
+
+typedef struct _GfsEventBalance GfsEventBalance;
+
+struct _GfsEventBalance {
+ GfsEvent parent;
+
+ gdouble max;
+};
+
+#define GFS_EVENT_BALANCE(obj) GTS_OBJECT_CAST (obj,\
+ GfsEventBalance,\
+ gfs_event_balance_class ())
+#define GFS_IS_EVENT_BALANCE(obj) (gts_object_is_from_class (obj,\
+ gfs_event_balance_class ()))
+
+GfsEventClass * gfs_event_balance_class (void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
-#endif /* __INIT_H__ */
+#endif /* __BALANCE_H__ */
diff --git a/src/domain.c b/src/domain.c
index 0ce0496..518c9ce 100644
--- a/src/domain.c
+++ b/src/domain.c
@@ -3849,41 +3849,78 @@ void gfs_domain_filter (GfsDomain * domain, GfsVariable * v, GfsVariable * fv)
gfs_domain_copy_bc (domain, FTT_TRAVERSE_LEAFS, -1, v, fv);
}
+struct _GfsRequest {
+ FILE * fp;
+ long length;
+#ifdef HAVE_MPI
+ MPI_Request request[2];
+ void * buf;
+#endif
+};
+
/**
* gfs_send_objects:
* @list: a list of #GtsObject.
* @dest: the rank of the destination PE.
*
* Sends the objects in @list to PE @dest of a parallel simulation.
+ * This is a non-blocking operation which returns a handler which must
+ * be cleared by calling gfs_wait().
*
* Note that this functions assumes that the write() method of the
* #GtsObject sent begins by writing the object class name.
+ *
+ * Returns: a #GfsRequest.
*/
-void gfs_send_objects (GSList * list, int dest)
+GfsRequest * gfs_send_objects (GSList * list, int dest)
{
#ifdef HAVE_MPI
- FILE * fp = tmpfile ();
- int fd = fileno (fp);
+ GfsRequest * r = g_malloc (sizeof (GfsRequest));
+ r->fp = tmpfile ();
+ int fd = fileno (r->fp);
struct stat sb;
while (list) {
GtsObject * object = list->data;
g_assert (object->klass->write != NULL);
- (* object->klass->write) (object, fp);
- fputc ('\n', fp);
+ (* object->klass->write) (object, r->fp);
+ fputc ('\n', r->fp);
list = list->next;
}
- fflush (fp);
+ fflush (r->fp);
g_assert (fstat (fd, &sb) != -1);
- long length = sb.st_size;
- MPI_Send (&length, 1, MPI_LONG, dest, 0, MPI_COMM_WORLD);
+ r->length = sb.st_size;
+ MPI_Isend (&r->length, 1, MPI_LONG, dest, 0, MPI_COMM_WORLD, &r->request[0]);
/* g_log (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, "sending %ld bytes to PE %d", length, dest); */
- if (length > 0) {
- char * buf = mmap (NULL, length, PROT_READ, MAP_PRIVATE, fd, 0);
- g_assert (buf != MAP_FAILED);
- MPI_Send (buf, length, MPI_BYTE, dest, 1, MPI_COMM_WORLD);
- munmap (buf, length);
+ if (r->length > 0) {
+ r->buf = mmap (NULL, r->length, PROT_READ, MAP_PRIVATE, fd, 0);
+ g_assert (r->buf != MAP_FAILED);
+ MPI_Isend (r->buf, r->length, MPI_BYTE, dest, 1, MPI_COMM_WORLD, &r->request[1]);
}
- fclose (fp);
+ return r;
+#else /* not HAVE_MPI */
+ return NULL;
+#endif /* HAVE_MPI */
+}
+
+/**
+ * gfs_wait:
+ * @r: a #GfsRequest.
+ *
+ * Waits for completion of and deallocates @r.
+ */
+void gfs_wait (GfsRequest * r)
+{
+#ifdef HAVE_MPI
+ g_return_if_fail (r != NULL);
+
+ MPI_Status status;
+ MPI_Wait (&r->request[0], &status);
+ if (r->length > 0) {
+ MPI_Wait (&r->request[1], &status);
+ munmap (r->buf, r->length);
+ }
+ fclose (r->fp);
+ g_free (r);
#endif /* HAVE_MPI */
}
@@ -3963,22 +4000,37 @@ static void setup_binary_IO (GfsDomain * domain)
domain->binary = TRUE;
}
-void gfs_send_boxes (GfsDomain * domain, GSList * boxes, int dest)
+/**
+ * gfs_send_boxes:
+ * @domain: a #GfsDomain.
+ * @boxes: a list of #GfsBox belonging to @domain.
+ * @dest: the destination processor id.
+ *
+ * Send boxes to @dest and removes them from @domain.
+ * This is a non-blocking operation.
+ *
+ * Returns: a #GfsRequest which must be cleared using gfs_wait().
+ */
+GfsRequest * gfs_send_boxes (GfsDomain * domain, GSList * boxes, int dest)
{
- g_return_if_fail (domain != NULL);
- g_return_if_fail (dest != domain->pid);
+ g_return_val_if_fail (domain != NULL, NULL);
+ g_return_val_if_fail (dest != domain->pid, NULL);
g_slist_foreach (boxes, (GFunc) unlink_box, &dest);
setup_binary_IO (domain);
- gfs_send_objects (boxes, dest);
+ GfsRequest * r = gfs_send_objects (boxes, dest);
g_slist_foreach (boxes, (GFunc) gts_object_destroy, NULL);
- if (boxes)
- gfs_domain_reshape (domain, gfs_domain_depth (domain));
+ return r;
}
/**
* gfs_receive_boxes:
- * @domain:
+ * @domain: a #GfsDomain.
+ * @src: the source processor id.
+ *
+ * Receive boxes from @src and adds them to @domain.
+ *
+ * Returns: the list of boxes received.
*/
GSList * gfs_receive_boxes (GfsDomain * domain, int src)
{
@@ -3994,8 +4046,6 @@ GSList * gfs_receive_boxes (GfsDomain * domain, int src)
/* Convert internal GfsBoundaryMpi into graph edges */
g_slist_foreach (boxes, (GFunc) convert_boundary_mpi_into_edges, ids);
g_ptr_array_free (ids, TRUE);
-
- gfs_domain_reshape (domain, gfs_domain_depth (domain));
}
return boxes;
}
diff --git a/src/domain.h b/src/domain.h
index ac811f5..2c38299 100644
--- a/src/domain.h
+++ b/src/domain.h
@@ -298,11 +298,13 @@ void gfs_domain_sum (GfsDomain * domain,
void gfs_domain_filter (GfsDomain * domain,
GfsVariable * v,
GfsVariable * fv);
-void gfs_send_objects (GSList * list,
+typedef struct _GfsRequest GfsRequest;
+GfsRequest * gfs_send_objects (GSList * list,
int dest);
+void gfs_wait (GfsRequest * r);
GSList * gfs_receive_objects (GfsDomain * domain,
int src);
-void gfs_send_boxes (GfsDomain * domain,
+GfsRequest * gfs_send_boxes (GfsDomain * domain,
GSList * boxes,
int dest);
GSList * gfs_receive_boxes (GfsDomain * domain,
diff --git a/src/event.c b/src/event.c
index cda9a48..9f74a2c 100644
--- a/src/event.c
+++ b/src/event.c
@@ -27,7 +27,6 @@
#include "event.h"
#include "solid.h"
#include "output.h"
-#include "mpi_boundary.h"
/**
* gfs_event_next:
@@ -1691,148 +1690,6 @@ GfsEventClass * gfs_event_script_class (void)
return klass;
}
-/* GfsEventBalance: Object */
-
-static void gfs_event_balance_write (GtsObject * o, FILE * fp)
-{
- GfsEventBalance * s = GFS_EVENT_BALANCE (o);
-
- if (GTS_OBJECT_CLASS (gfs_event_balance_class ())->parent_class->write)
- (* GTS_OBJECT_CLASS (gfs_event_balance_class ())->parent_class->write)
- (o, fp);
-
- fprintf (fp, " %g", s->max);
-}
-
-static void gfs_event_balance_read (GtsObject ** o, GtsFile * fp)
-{
- GfsEventBalance * s = GFS_EVENT_BALANCE (*o);
- GfsDomain * domain = GFS_DOMAIN (gfs_object_simulation (s));
-
- if (GTS_OBJECT_CLASS (gfs_event_balance_class ())->parent_class->read)
- (* GTS_OBJECT_CLASS (gfs_event_balance_class ())->parent_class->read)
- (o, fp);
- if (fp->type == GTS_ERROR)
- return;
-
- s->max = gfs_read_constant (fp, domain);
-}
-
-static void count (FttCell * cell, int * n)
-{
- (*n)++;
-}
-
-typedef struct {
- GfsBox * box;
- gint dest, n, min, neighboring;
-} BoxData;
-
-#define LAMBDA 0.3
-
-static void select_neighbouring_box (GfsBox * box, BoxData * b)
-{
- gint neighboring = 0;
- FttDirection d;
-
- for (d = 0; d < FTT_NEIGHBORS && !neighboring; d++)
- if (GFS_IS_BOUNDARY_MPI (box->neighbor[d]) &&
- GFS_BOUNDARY_MPI (box->neighbor[d])->process == b->dest)
- neighboring++;
-
- if (neighboring) {
- box->size = 0;
- ftt_cell_traverse (box->root, FTT_PRE_ORDER, FTT_TRAVERSE_LEAFS, -1,
- (FttCellTraverseFunc) count, &(box->size));
- if (!b->box ||
- (fabs (box->size - b->n) < (1. - LAMBDA)*fabs (b->box->size - b->n)) ||
- (fabs (box->size - b->n) < (1. + LAMBDA)*fabs (b->box->size - b->n) &&
- neighboring > b->neighboring)) {
- b->box = box;
- b->neighboring = neighboring;
- }
- }
-}
-
-static gboolean gfs_event_balance_event (GfsEvent * event, GfsSimulation * sim)
-{
- if ((* GFS_EVENT_CLASS (GTS_OBJECT_CLASS (gfs_event_balance_class ())->parent_class)->event)
- (event, sim)) {
- GfsDomain * domain = GFS_DOMAIN (sim);
- GfsEventBalance * s = GFS_EVENT_BALANCE (event);
- GtsRange size, boundary, mpiwait;
-
- gfs_domain_stats_balance (domain, &size, &boundary, &mpiwait);
- if (size.max/size.min > s->max) {
-#ifdef HAVE_MPI
- int n, other;
- MPI_Comm_size (MPI_COMM_WORLD, &n);
- if (n != 2)
- g_assert_not_implemented ();
-
- n = 0;
- gfs_domain_cell_traverse (domain, FTT_PRE_ORDER, FTT_TRAVERSE_LEAFS, -1,
- (FttCellTraverseFunc) count, &n);
- other = (domain->pid + 1) % 2;
- if (n > size.mean) { /* largest subdomain */
- if (gts_container_size (GTS_CONTAINER (domain)) < 2)
- gfs_send_boxes (domain, NULL, other);
- else {
- n -= size.mean;
-
- BoxData b;
- b.box = NULL; b.n = n;
- b.dest = other;
- /* we need to find the list of boxes which minimizes
- |\sum n_i - n| where n_i is the size of box i. This is known in
- combinatorial optimisation as a "knapsack problem". */
- gts_container_foreach (GTS_CONTAINER (domain), (GtsFunc) select_neighbouring_box, &b);
- if (b.box && b.box->size <= size.max - size.min) {
- GSList * l = g_slist_prepend (NULL, b.box);
- gfs_send_boxes (domain, l, other);
- g_slist_free (l);
- }
- else
- gfs_send_boxes (domain, NULL, other);
- }
- }
- else /* smallest subdomain */
- g_slist_free (gfs_receive_boxes (domain, other));
-#endif
- }
- return TRUE;
- }
- return FALSE;
-}
-
-static void gfs_event_balance_class_init (GfsEventClass * klass)
-{
- GTS_OBJECT_CLASS (klass)->read = gfs_event_balance_read;
- GTS_OBJECT_CLASS (klass)->write = gfs_event_balance_write;
- GFS_EVENT_CLASS (klass)->event = gfs_event_balance_event;
-}
-
-GfsEventClass * gfs_event_balance_class (void)
-{
- static GfsEventClass * klass = NULL;
-
- if (klass == NULL) {
- GtsObjectClassInfo gfs_event_balance_info = {
- "GfsEventBalance",
- sizeof (GfsEventBalance),
- sizeof (GfsEventClass),
- (GtsObjectClassInitFunc) gfs_event_balance_class_init,
- (GtsObjectInitFunc) NULL,
- (GtsArgSetFunc) NULL,
- (GtsArgGetFunc) NULL
- };
- klass = gts_object_class_new (GTS_OBJECT_CLASS (gfs_event_class ()),
- &gfs_event_balance_info);
- }
-
- return klass;
-}
-
/* GfsInitFraction: Object */
static void gfs_init_fraction_destroy (GtsObject * object)
diff --git a/src/event.h b/src/event.h
index 9d6a270..ceaf86f 100644
--- a/src/event.h
+++ b/src/event.h
@@ -251,24 +251,6 @@ struct _GfsEventScript {
GfsEventClass * gfs_event_script_class (void);
-/* GfsEventBalance: Header */
-
-typedef struct _GfsEventBalance GfsEventBalance;
-
-struct _GfsEventBalance {
- GfsEvent parent;
-
- gdouble max;
-};
-
-#define GFS_EVENT_BALANCE(obj) GTS_OBJECT_CAST (obj,\
- GfsEventBalance,\
- gfs_event_balance_class ())
-#define GFS_IS_EVENT_BALANCE(obj) (gts_object_is_from_class (obj,\
- gfs_event_balance_class ()))
-
-GfsEventClass * gfs_event_balance_class (void);
-
/* GfsInitFraction: Header */
typedef struct _GfsInitFraction GfsInitFraction;
diff --git a/src/init.c b/src/init.c
index b0064a8..91c0d68 100644
--- a/src/init.c
+++ b/src/init.c
@@ -42,6 +42,7 @@
#include "solid.h"
#include "moving.h"
#include "river.h"
+#include "balance.h"
#include "modules.h"
diff --git a/src/mpi_boundary.c b/src/mpi_boundary.c
index e0063f5..8951196 100644
--- a/src/mpi_boundary.c
+++ b/src/mpi_boundary.c
@@ -74,6 +74,7 @@ fprintf (DEBUG, "%d send to %d with tag %d match variable size\n",
domain->pid,
mpi->process,
TAG (GFS_BOUNDARY (boundary)));
+fflush (DEBUG);
#endif
MPI_Isend (&boundary->sndcount, 1, MPI_UNSIGNED,
mpi->process,
@@ -88,6 +89,7 @@ fprintf (DEBUG, "%d send to %d with tag %d, size %d\n",
mpi->process,
TAG (GFS_BOUNDARY (boundary)),
boundary->sndcount);
+fflush (DEBUG);
#endif
MPI_Isend (boundary->sndbuf->data, boundary->sndcount, MPI_DOUBLE,
mpi->process,
@@ -124,6 +126,7 @@ fprintf (DEBUG, "%d wait on %d with tag %d for match variable size\n",
gfs_box_domain (bb->box)->pid,
mpi->process,
MATCHING_TAG (GFS_BOUNDARY (boundary)));
+fflush (DEBUG);
#endif
MPI_Recv (&boundary->rcvcount, 1, MPI_UNSIGNED,
mpi->process,
@@ -145,6 +148,7 @@ fprintf (DEBUG, "%d wait on %d with tag %d for match variable size\n",
gfs_box_domain (bb->box)->pid,
mpi->process,
MATCHING_TAG (GFS_BOUNDARY (boundary)));
+fflush (DEBUG);
#endif
g_assert (boundary->rcvcount <= boundary->rcvbuf->len);
MPI_Recv (boundary->rcvbuf->data,
@@ -207,6 +211,7 @@ static void synchronize (GfsBoundary * bb)
/* rewind (DEBUG); */
fprintf (DEBUG, "==== %d synchronised ====\n",
gfs_box_domain (bb->box)->pid);
+ fflush (DEBUG);
#endif
(* gfs_boundary_periodic_class ()->synchronize) (bb);
}
--
Gerris Flow Solver
More information about the debian-science-commits
mailing list