Subject: Re: Buffer descriptor generalization

From: [email-masked] (Ricardo Schmutzer von Oldershausen)
Date: Wed, 9 Jun 93 15:03:28 AST

Hello !

I am very enthusiastic about James Cownie's proposal because now, it is 
not necessary any more to describe a complex structure each time you 
create a new buffer.  Now, you just describe the type of the structure
with an unbound buffer _once_, and you call MPI_APPEND_CONTIGUOUS each
time you want to create a new buffer of that type (after MPI_CREATE_BUFFER).
This simplifies the implementation and usage of user-types.  This will
also allow to implement a stub generator ('mpigen' ?) which generates
the code to describe the unbound buffer from a source language type 
declaration automatically (reducing programming errors; similar as 
'rpcgen' generates XDR functions for RPC).

Unfortunetly, as the buffer building functions MPI_APPEND_* have been
designed to build a buffer when the data to be sent is already known
(amount and type), is seems to be impossible to describe a type with
an unbound buffer, if the type contains an array of variable length or 
if it contains a union (I am writing this rather late, so you may have
discussed this already ; my apologies in that case for placing this 
letter in the forum ...).

Let me explain this with two examples:

1) Arrays of variable length:

Let's suppose you want to send the following structure (inside a more
complex one; simplified for the example):

#define MAX_ARRAY_LENGTH 1000

struct var_array {
	int array_length;
	double array[MAX_ARRAY_LENGTH];
};

which describes an array of variable length with a maximum size
MAX_ARRAY_LENGTH, but where we actually use only the first array_length
elements.

Therefore we also want to send only the first array_length elements.

Describing the buffer inmediately before sending, there is no problem,
because we do have a value for array_length:

struct variable_array foo1;
MPI_BUFFER b;

MPI_CREATE_BUFFER(&b, MPI_EPHEMERAL);
MPI_APPEND_CONTIGUOUS(b, &foo1.array, foo1.array_length, MPI_DOUBLE);
MPI_COMMIT(b);

But how do we describe this type (struct var_array) with an unbound
buffer ?  One solution could be:

MPI_BUFFER b;

MPI_CREATE_BUFFER(&b, MPI_PERSISTENCE);
MPI_APPEND_CONTIGUOUS(b, (struct var_array *)0, MAX_ARRAY_LENGTH, MPI_DOUBLE);
MPI_COMMIT(b);

We cant't use array_length, because the value is still not known.
This has the problem, that MPI will send all 1000 (MAX_LENGTH_ARRAY) elements,
even if only the first 10 are used.

A possible solution is to implement a slight modified version of
MPI_APPEND_CONTIGUOUS (or better yet: of MPI_APPEND_VEC):

MPI_APPEND_ARRAY(buffer, start, length, max_count, stride, ?, datatype)

where a parameter receives a pointer to the array length (I do not remember
if an unbound buffer must have MPI_NULL in his start parameter.  In that case,
instead of a pointer the new parameter would have to be an offset in bytes from
the start parameter):

MPI_BUFFER b;

MPI_CREATE_BUFFER(&b, MPI_PERSISTENCE);
MPI_APPEND_ARRAY(b, (struct var_array *)0->array, 
		&((struct var_array *)0)->array_length,
		MAX_ARRAY_LENGTH, 1, 1, MPI_DOUBLE);
MPI_COMMIT(b);

Note, that the count parameter is preserved to allow the proper alignment if
this array is inside a more complex structure (see the declaration of var_array).

This function would allow us to describe types with arrays of variable length.

Discussion: Is there also a need for a MPI_APPEND_HARRAY function ?

2) Unions

Here we have an analogous problem, only that instead of not knowing the length
of the array in advance, we do not know the type of the data in advance:

struct foo_type {
	int type;
	union {
		int i;
		double d;
		char c;
	} foo_union;
};
 
Describing the buffer inmediately before sending, there is no problem,
because we do know the data type:

struct foo_type foo2;
MPI_BUFFER b;

MPI_CREATE_BUFFER(&b, MPI_EPHEMERAL);
MPI_APPEND_CONTIGUOUS(b, &foo2.type, 1, MPI_INT);
switch (foo2.type) {
	case 0:
		MPI_APPEND_CONTIGUOUS(b, &foo2.foo_union.i, 1, MPI_INT);
	case 1:
		MPI_APPEND_CONTIGUOUS(b, &foo2.foo_union.d, 1, MPI_DOUBLE);
	case 2:
		MPI_APPEND_CONTIGUOUS(b, &foo2.foo_union.c, 1, MPI_CHAR);
};
MPI_COMMIT(b);

But we are unable to describe this type with an unbound buffer, because
the type is not known in advance.

A solution could be to define a function:

MPI_APPEND_UNION(buffer, start, type, size, count, array_of_types)

where buffer is the MPI_BUFFER,
start is the location of the union,
array_of_types is an array of MPI_BUFFERs,
count is the length of array_of_types
type is a pointer to an integer index into array_of_types
     (if the start parameter in an unbound buffer must be MPI_NULL,
     than type should be an offset in bytes from start)
and size is the length of the union in bytes.

So, the unbound buffer may be described as follows:

MPI_BUFFER b;
MPI_BUFFER types[3] = { MPI_INT, MPI_DOUBLE, MPI_CHAR };

MPI_CREATE_BUFFER(&b, MPI_PERSISTENCE);
MPI_APPEND_UNION(b, ((struct foo_type *)0)->foo_union, 
	&((struct foo_type *)0)->type, MPI_DOUBLE_SIZE, 3, types);
MPI_COMMIT(b);

I think, the size paramenter is needed to simplify alignment inside a more
complex structure, specially if the types in the array_of_types are user-types.
In that case, we would need a function MPI_SIZEOF(buffer) (or similar), if the
size parameter would not exist.

===============================================================================

The functions MPI_APPEND_ARRAY and MPI_APPEND_UNION follow the following goals:

1) Allow to describe user-types with unbound buffers, that contain variable
   length arrays or unions
2) Simplify the description of user-types
3) Allow to implement (at least in theory) a generator of code for unbound
   buffers from the source code type description. This would minimize
   development errors and would simplify the interface of MPI for users.

Ricardo.
-- 
+----------------------+---------------------------------+--------------+
| Ricardo A. Schmutzer | Internet: [email-masked]    | Conectividad |
| PUC, Santiago, Chile |                                 | Distr. Comp. |
+----------------------+---------------------------------+--------------+