in MPI/Intercommunicator.cs [653:730]
public void Alltoall<T>(T[] inValues, ref T[] outValues)
{
// Make sure the outgoing array is the right size
if (outValues == null || outValues.Length != inValues.Length)
outValues = new T[inValues.Length];
MPI_Datatype datatype = FastDatatypeCache<T>.datatype;
if (datatype == Unsafe.MPI_DATATYPE_NULL)
{
// There is no associated MPI datatype for this type, so we will
// need to serialize the value for transmission.
int[] sendCounts = new int[RemoteSize];
int[] sendOffsets = new int[RemoteSize];
using (UnmanagedMemoryStream sendStream = new UnmanagedMemoryStream())
{
// Serialize all of the outgoing data to the outgoing stream
for (int dest = 0; dest < RemoteSize; ++dest)
{
sendOffsets[dest] = Convert.ToInt32(sendStream.Length);
Serialize(sendStream, inValues[dest]);
sendCounts[dest] = checked(Convert.ToInt32(sendStream.Length) - sendOffsets[dest]);
}
// Use all-to-all on integers to tell every process how much data
// it will be receiving.
int[] recvCounts = Alltoall(sendCounts);
// Compute the offsets at which each of the streams will be received
int[] recvOffsets = new int[RemoteSize];
recvOffsets[0] = 0;
for (int i = 1; i < RemoteSize; ++i) checked
{
recvOffsets[i] = recvOffsets[i - 1] + recvCounts[i - 1];
}
// Total length of the receive buffer
int recvLength = checked(recvOffsets[RemoteSize - 1] + recvCounts[RemoteSize - 1]);
using (UnmanagedMemoryStream recvStream = new UnmanagedMemoryStream(recvLength))
{
// Build receive buffer and exchange all of the data
unsafe
{
int errorCode = Unsafe.MPI_Alltoallv(sendStream.Buffer, sendCounts, sendOffsets, Unsafe.MPI_BYTE,
recvStream.Buffer, recvCounts, recvOffsets, Unsafe.MPI_BYTE, comm);
if (errorCode != Unsafe.MPI_SUCCESS)
throw Environment.TranslateErrorIntoException(errorCode);
}
// De-serialize the received data
for (int source = 0; source < RemoteSize; ++source)
{
// Seek to the proper location in the stream and de-serialize
recvStream.Position = recvOffsets[source];
outValues[source] = Deserialize<T>(recvStream);
}
}
}
}
else
{
GCHandle inHandle = GCHandle.Alloc(inValues, GCHandleType.Pinned);
GCHandle outHandle = GCHandle.Alloc(outValues, GCHandleType.Pinned);
int errorCode;
unsafe
{
errorCode = Unsafe.MPI_Alltoall(Marshal.UnsafeAddrOfPinnedArrayElement(inValues, 0), 1, datatype,
Marshal.UnsafeAddrOfPinnedArrayElement(outValues, 0), 1, datatype, comm);
}
inHandle.Free();
outHandle.Free();
if (errorCode != Unsafe.MPI_SUCCESS)
throw Environment.TranslateErrorIntoException(errorCode);
}
}