MPI_Upack inside userd define operation of MPI_reduce() - c

I have to send a struct that contains, among other things, a dynamically allocated array of another struct.
The receiver has to merge the received message with its data and then send the result to another process.
Basically what I want to obtain is something like that.
I have implemented the following code.
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
typedef struct Data {
char character;
int frequency;
} Data;
typedef struct Dictionary {
int charsNr;
Data *data;
} Dictionary;
typedef struct Header {
int id;
int size;
MPI_Datatype *type;
int position;
} Header;
static const int NUM_CHARS = 5;
typedef unsigned char BYTE;
void buildMyTypr(MPI_Datatype *dictType) {
int blockLengths[] = {1, 1};
MPI_Datatype types[] = {MPI_CHAR, MPI_INT};
MPI_Aint offsets[2];
offsets[0] = offsetof(Data, character);
offsets[1] = offsetof(Data, frequency);
MPI_Type_create_struct(2, blockLengths, offsets, types, dictType);
MPI_Type_commit(dictType);
}
void appendData(Dictionary *dict, Data *data) {
dict->data = realloc(dict->data, sizeof(Data) * (dict->charsNr+1));
dict->data[dict->charsNr] = (struct Data) {.character = data->character, .frequency = data->frequency};
++dict->charsNr;
}
void mergeDicts(Dictionary *dst, Dictionary *src) {
for (int i = 0; i < src->charsNr; i++) {
char character = src->data[i].character;
int frequency = src->data[i].frequency;
bool assigned = false;
for (int j = 0; j < dst->charsNr && !assigned; j++) {
if (dst->data[j].character == character) {
dst->data[j].frequency += frequency;
assigned = true;
}
}
if (!assigned)
appendData(dst, &src->data[i]);
}
}
int getRand(const int from, const int to)
{
int num = (rand() % (to - from + 1)) + from;
return num;
}
void getMessageSize(int *size, int rank, int tag, MPI_Status *status) {
MPI_Probe(rank, tag, MPI_COMM_WORLD, status);
MPI_Get_count(status, MPI_BYTE, size);
}
BYTE* packDictionary(Header *header, Dictionary *dict) {
header->size = sizeof(int) + (sizeof(Data) * dict->charsNr);
BYTE *buffer = malloc(sizeof(BYTE) * (header->size));
header->position = 0;
MPI_Pack(&dict->charsNr, 1, MPI_INT, buffer, header->size, &header->position, MPI_COMM_WORLD);
MPI_Pack(dict->data, dict->charsNr, *header->type, buffer, header->size, &header->position, MPI_COMM_WORLD);
return buffer;
}
void unpackDictionary(Header *header, Dictionary *dict, BYTE *buffer) {
MPI_Unpack(buffer, header->size, &header->position, &dict->charsNr, 1, MPI_INT, MPI_COMM_WORLD);
dict->data = malloc(sizeof(Data) * dict->charsNr);
MPI_Unpack(buffer, header->size, &header->position, dict->data, dict->charsNe, *header->type, MPI_COMM_WORLD);
}
void MyTypeOp(contType *in, contType *out, int *len, MPI_Datatype *typeptr)
{
MPI_Status *status;
Dictionary inDict = {.charsNr = 0, .data = NULL};
Dictionary outDict = {.charsNr = 0, .data = NULL};
int bufferSize = 0;
// how can I get the size of the buffers?
// in other occasion I use the getMessageSize(), but I'm not sure
// if it can be useful here
// how can I get the type of the message, basically the dictType?
Header header = {.id = 0, .size = 0, .type = NULL, .position = 0};
unpackDictionary(&header, &inDict, in);
// I should update the header with the new size
unpackDictionary(&header, &outDict, out);
mergeDicts(&outDict, &inDict);
header.size = 0;
out = packDictionary(header, &outDict);
}
int main(int argc, char **argv)
{
int proc_number;
int rank;
MPI_Comm_size(MPI_COMM_WORLD, &proc_number);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
Dictionary dict = {.charsNr = NUM_CHARS, .data = NULL};
dict.data = malloc(dict.charsNr * sizeof(Data));
// create a random dictionary
// I use for simplicity NUM_CHARS but in real life it will be unknown
// at the beginning and every dictionary can have a different size
for (int i = 0; i < NUM_CHARS; i++) {
int freq = getRand(1, 10);
dict.data[i].frequency = freq;
dict.data[i].character = 'a' + getRand(1, 5) + i + rank;
}
MPI_Datatype dictType;
buildMyType(&dictType);
MPI_Op MyOp;
MPI_Op_create((MPI_User_function *) MyTypeOp, 1, &MyOp);
MPI_Datatype contType;
MPI_Type_contiguous(1, MPI_PACKED, &contType);
MPI_Type_commit(&contType);
Header header = {.id = 0, .size = 0, .type = &dictType, .position = 0};
// when I pack the message I put everithing inside a buffer of BYTE
BYTE *buffer = packDictionary(&header, &dict);
BYTE *buffer_rcv = NULL;
MPI_Reduce(&buffer,& buffer_rcv, 1, contType, MyOp, 0, MPI_COMM_WORLD);
if(rank == 0)
for (i = 0; i < NUM_CHARS; i++)
printf("%c: %d\n", dict.data[i].character, dict.data[i].frequency);
MPI_Type_free(&contType);
MPI_Type_free(&dictType);
MPI_Op_free(&MyOp);
free(buffer);
free(buffer_rcv);
free(dict.data);
MPI_Finalize();
return 0;
}
Of course this example cannot run.
Do you have any suggestion on how can I do it?
I'm writing the code in C on Linux machine.
Thanks.

Related

SZ_ERROR_DATA from LzmaDecode function (C lzma)

I have an array of numbers which i want to compress and store in a file then decompress and put data in a buffer.
RAM->FILE compressing
FILE->RAM decompressing
I used LzmaEncode for compressing and then write compress buffer in a file.
lzmaencoder.c
int main(void){
int data[] = {1,2,3,4,5};
size_t src_len = sizeof(data);
const Byte * src = (Byte *) data;
size_t compressed_size = src_len*1.5;
Byte * compressed_data = malloc(compressed_size);
CLzmaEncProps props;
LzmaEncProps_Init(&props);
Byte header[LZMA_PROPS_SIZE];
size_t headerSize = LZMA_PROPS_SIZE;
// Call encoding function:
SRes res;
res = LzmaEncode(compressed_data, &compressed_size, src, src_len,
&props, header, &headerSize, 0, NULL, &g_Alloc, &g_Alloc);
if(res == SZ_OK){
FILE * file = fopen("lzma_file","wb");
fwrite(compressed_data, sizeof(Byte), compressed_size, file);
}
free(compressed_data);
return (0);
}
I read compress file and write data in a buffer, then use LzmaDecode for decompressing.
lzmadecoder.c
int main(int argc, char * argv[]){
// I know the original data size
size_t uncompress_size = 20;
Byte * uncompress = malloc(uncompress_size);
// open compressed file
size_t compress_size;
FILE * compress_file = fopen("lzma_file", "rb");
if(!compress_file){
printf("Error: can not open lzma_file file.");
}
// get compressed file size
fseek(compress_file, 0, SEEK_END);
compress_size = ftell(compress_file);
fseek(compress_file, 0, SEEK_SET);
Byte *compress_data = malloc(compress_size);
// put compressed file data on RAM
if(!fread(compress_data, sizeof(Byte), compress_size, compress_file)){
printf("Error: can not read lzma_file file.");
}
fclose(compress_file);
ELzmaStatus status;
// RAM->RAM decompressing
int res = LzmaDecode(uncompress, &uncompress_size,
compress_data, &compress_size,
compress_data, 5,
LZMA_FINISH_END, &status, &g_Alloc);
if(res==SZ_OK){
printf("SZ_OK!\n");
} else if(res==SZ_ERROR_DATA){
printf("SZ_ERROR_DATA!\n");
}
free(uncompress);
free(compress_data);
return (0);
}
but LzmaDecode return SZ_ERROR_DATA. I cant find my problem.
LZMA compression---------------- Version: 9.35
Use the Lib API generated by the project "lzma1900\C\Util\LzmaLib": LzmaCompress and LzmaUncompress.
int main()
{
Byte outProps[5];
size_t outPropsSize = 5; /* *outPropsSize must be = 5 */
int r =RawEncode(out,&tmpLen,bnInfo, len1,outProps,&outPropsSize);
Pkt init =RawDecode(out2,$outLen2, out, tmpLen, &outPropsSize);
return 0;
}
int RawEncode(char* out, int *ol, char *buf, uint32_t l, char* outProps, size_t* outPropsSize)
{
int res = 0;
m_l = 8;
int level = m_level; /* 0 <= level <= 9, default = 5 */
unsigned dictSize = 1 << 24; /* default = (1 << 24) */
int lc = 3; /* 0 <= lc <= 8, default = 3 */
int lp = 0; /* 0 <= lp <= 4, default = 0 */
int pb = 2; /* 0 <= pb <= 4, default = 2 */
int fb = 32; /* 5 <= fb <= 273, default = 32 */
int numThreads = 1; /* 1 or 2, default = 2 */
int r = LzmaCompress(out,ol,buf,l,outProps, outPropsSize, m_level, dictSize, lc, lp, pb, fb, 1);
olen = l;
return r;
}
void RawDecode(char* out, int* oLen, char* buf, int len, unsigned char* props, size_t* propsSize)
{
char out[outLen];
SizeT srcLen = pkt.first.len - 8;
int r = LzmaUncompress(out, oLen, buf, &len, props, *propsSize);
if(SZ_OK != r)
{
printf("LzmaUncompress error %d.", r);
delete [] tmp.second;
tmp.second = NULL;
}
}

Handle is invalid

Trying to use SetConsoleScreenBufferSize but it fails and puts "The handle is invalid." In the last error. Will post all code, but here are some highlights:
Using this to resize buffer:
int TGHandleResizeEvent(struct TGHandle *tgHandle, INPUT_RECORD record) {
if (record.EventType == WINDOW_BUFFER_SIZE_EVENT) {
WINDOW_BUFFER_SIZE_RECORD size = record.Event.WindowBufferSizeEvent;
sizeTGDrawBuffer(&tgHandle->drawBuffer, size.dwSize.X, size.dwSize.Y);
clearTGDrawBuffer(&tgHandle->drawBuffer);
COORD bufferNewSize = {
size.dwSize.X,
size.dwSize.Y
};
return SetConsoleScreenBufferSize(&tgHandle->screenBufferHandle, bufferNewSize);
}
}
Using this to allocate handle:
struct TGHandle TG() {
struct TGHandle tgHandle;
tgHandle.screenBufferHandle = CreateConsoleScreenBuffer(
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL
);
CONSOLE_SCREEN_BUFFER_INFO info;
GetConsoleScreenBufferInfo(tgHandle.screenBufferHandle, &info);
tgHandle.drawBuffer = createTGDrawBuffer(info.dwSize.X, info.dwSize.Y);
// Create the input buffer
tgHandle.inputBufferSize = 32;
tgHandle.inputBuffer = malloc(sizeof(INPUT_RECORD) * tgHandle.inputBufferSize);
// Hook up the input handle
tgHandle.inputHandle = GetStdHandle(STD_INPUT_HANDLE);
return tgHandle;
}
Here is full code.
tg.h
#ifndef TG_H
#define TG_H
#include <Windows.h>
#include <memory.h>
#define FOREGROUND_WHITE FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
#define BACKGROUND_WHITE BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
// A drawing buffer, for general purposes
struct TGDrawBuffer {
COORD size;
CHAR_INFO *buffer;
};
struct TGDrawBuffer createTGDrawBuffer(int, int); // Function to allocate a drawing buffer
void sizeTGDrawBuffer(struct TGDrawBuffer*, int, int); // Resize a draw buffer
void clearTGDrawBuffer(struct TGDrawBuffer*); // Fill a buffer with blank cells
void TGDrawPixel(struct TGDrawBuffer*, int, int, CHAR_INFO); // Draw to a single cell on the buffer
void TGDrawAttribute(struct TGDrawBuffer*, int, int, int); // Modify a single attribute. X, Y, Attr
void TGDrawCharInfoString(struct TGDrawBuffer*, int, int, CHAR_INFO*, int); // X, Y, string, int. Draws to max X
CHAR_INFO* TGCharToCharInfo(char*, int); // Convert basic characters to CHAR_INFO. String, length.
void TGDrawString(struct TGDrawBuffer*, int, int, char*, int); // X, Y, string, length. Draws to max X
void freeTGDrawBuffer(struct TGDrawBuffer*); // Function to de-allocate a drawing buffer
int CharInfoStrlen(CHAR_INFO*); // Get length of a CHAR_INFO as if it were a string
// Essentially a drawing context to the screen
struct TGHandle {
HANDLE screenBufferHandle, inputHandle;
struct TGDrawBuffer drawBuffer;
INPUT_RECORD *inputBuffer;
int inputBufferSize;
};
struct TGHandle TG(); // Initialization function, which returns a drawing context to the screen
void useTGHandle(struct TGHandle*); // Make a screen drawing context active
void updateTGHandle(struct TGHandle*); // Displays what has been drawn
void setTGHandleCursorVisibility(struct TGHandle*, int); // True / False
int getTGInput(struct TGHandle*, INPUT_RECORD*, int); // Fill input into a buffer
int getTGNextInput(struct TGHandle*, INPUT_RECORD*); // Get a single INPUT_RECORD or return false
int TGHandleResizeEvent(struct TGHandle*, INPUT_RECORD); // Resize is not handled automatically
#endif
tg.c
#include "tg.h"
#include <string.h>
struct TGDrawBuffer createTGDrawBuffer(int width, int height) {
struct TGDrawBuffer tgDrawBuffer;
tgDrawBuffer.buffer = NULL; // Init the buffer to NULL
sizeTGDrawBuffer(&tgDrawBuffer, width, height);
return tgDrawBuffer;
}
void sizeTGDrawBuffer(struct TGDrawBuffer* drawBuffer, int width, int height) {
// Using free/ malloc here because we aren't interested in retaining data
if (drawBuffer->buffer) {
free(drawBuffer->buffer);
}
drawBuffer->buffer = malloc(sizeof(CHAR_INFO) * (width * height));
// Copy the size to the buffer record
drawBuffer->size.X = width;
drawBuffer->size.Y = height;
}
void clearTGDrawBuffer(struct TGDrawBuffer *tgBuffer) {
int i = 0, limit = tgBuffer->size.X * tgBuffer->size.Y;
// Create a blank CHAR_INFO
CHAR_INFO clearChar;
clearChar.Char.AsciiChar = ' ';
clearChar.Char.UnicodeChar = ' ';
clearChar.Attributes = FOREGROUND_WHITE; // Would be confusing without this
// Set everything to that buffer
while (i < limit) {
tgBuffer->buffer[i] = clearChar;
i++;
}
}
void TGDrawPixel(struct TGDrawBuffer *tgBuffer, int x, int y, CHAR_INFO character) {
tgBuffer->buffer[(tgBuffer->size.X * y) + x] = character;
}
void TGDrawAttribute(struct TGDrawBuffer *tgBuffer, int x, int y, int attr) {
tgBuffer->buffer[(tgBuffer->size.X * y) + x].Attributes = attr;
}
void TGDrawCharInfoString(struct TGDrawBuffer *tgDrawBuffer, int x, int y, CHAR_INFO *string, int length) {
int charsToWrite = length;
int distanceToEnd = (tgDrawBuffer->size.Y - 1) - y;
if (distanceToEnd < charsToWrite)
distanceToEnd = charsToWrite;
int startPos = x + (tgDrawBuffer->size.X * y);
int i = 0;
while (i < distanceToEnd) {
tgDrawBuffer->buffer[startPos + x] = string[i];
i++;
}
}
CHAR_INFO* TGCharToCharInfo(char* string, int length) {
if (length == -1)
length = strlen(string);
// TODO
}
void TGDrawString(struct TGDrawBuffer *tgDrawBuffer, int x, int y, char *string, int length) {
int charsToWrite = length;
int distanceToEnd = (tgDrawBuffer->size.Y - 1) - y;
if (distanceToEnd < charsToWrite)
charsToWrite = distanceToEnd;
int startPos = x + (tgDrawBuffer->size.X * y);
int i = 0;
while (i < charsToWrite) {
tgDrawBuffer->buffer[startPos + i].Char.AsciiChar = string[i];
tgDrawBuffer->buffer[startPos + i].Char.UnicodeChar = string[i];
i++;
}
}
void freeTGDrawBuffer(struct TGDrawBuffer *drawBuffer) {
free(drawBuffer->buffer);
}
struct TGHandle TG() {
struct TGHandle tgHandle;
tgHandle.screenBufferHandle = CreateConsoleScreenBuffer(
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CONSOLE_TEXTMODE_BUFFER,
NULL
);
CONSOLE_SCREEN_BUFFER_INFO info;
GetConsoleScreenBufferInfo(tgHandle.screenBufferHandle, &info);
tgHandle.drawBuffer = createTGDrawBuffer(info.dwSize.X, info.dwSize.Y);
// Create the input buffer
tgHandle.inputBufferSize = 32;
tgHandle.inputBuffer = malloc(sizeof(INPUT_RECORD) * tgHandle.inputBufferSize);
// Hook up the input handle
tgHandle.inputHandle = GetStdHandle(STD_INPUT_HANDLE);
return tgHandle;
}
void useTGHandle(struct TGHandle *tgHandle) {
SetConsoleActiveScreenBuffer(tgHandle->screenBufferHandle);
// Update the buffer sizes
CONSOLE_SCREEN_BUFFER_INFO info;
GetConsoleScreenBufferInfo(tgHandle->screenBufferHandle, &info);
sizeTGDrawBuffer(&tgHandle->drawBuffer, info.dwSize.X, info.dwSize.Y);
clearTGDrawBuffer(&tgHandle->drawBuffer);
}
void updateTGHandle(struct TGHandle *tgHandle) {
COORD size = { tgHandle->drawBuffer.size.X, tgHandle->drawBuffer.size.Y }; // Buffer size
COORD pos = { 0, 0 }; // Start of the buffer coord
SMALL_RECT rect = {
.Left = 0,
.Top = 0,
.Right = size.X - 1,
.Bottom = size.Y - 1
}; // Rect to draw to on destination
WriteConsoleOutput(
tgHandle->screenBufferHandle,
tgHandle->drawBuffer.buffer,
size,
pos,
&rect
);
}
void setTGHandleCursorVisibility(struct TGHandle *tgHandle, int visible) {
// Copy the already-available cursor info
CONSOLE_CURSOR_INFO info;
GetConsoleCursorInfo(tgHandle->screenBufferHandle, &info);
// Modify the cursor visibility
info.bVisible = visible;
SetConsoleCursorInfo(tgHandle->screenBufferHandle, &info);
}
// You should be able to use a TGHandle's input buffer rather than creating your own
// for maximum memory conservation
int getTGInput(struct TGHandle *tgHandle, INPUT_RECORD *inputBuffer, int max) {
int availableRecords;
GetNumberOfConsoleInputEvents(tgHandle->inputHandle, &availableRecords);
int amountToRead = max;
if (availableRecords < max) {
amountToRead = availableRecords;
}
int numberRead;
ReadConsoleInput(
tgHandle->inputHandle,
inputBuffer,
amountToRead,
&numberRead
);
return numberRead;
}
// This function should be pretty performant if someone would not like to use
// the above function and mess around with buffers.
// Input record info: https://learn.microsoft.com/en-us/windows/console/input-record-str
int getTGNextInput(struct TGHandle *tgHandle, INPUT_RECORD *record) {
int availableRecords;
GetNumberOfConsoleInputEvents(tgHandle->inputHandle, &availableRecords);
if (availableRecords == 0) {
return 0;
}
ReadConsoleInput(
tgHandle->inputHandle,
tgHandle->inputBuffer,
1,
&availableRecords
);
*record = tgHandle->inputBuffer[0];
return 1;
}
int TGHandleResizeEvent(struct TGHandle *tgHandle, INPUT_RECORD record) {
if (record.EventType == WINDOW_BUFFER_SIZE_EVENT) {
WINDOW_BUFFER_SIZE_RECORD size = record.Event.WindowBufferSizeEvent;
sizeTGDrawBuffer(&tgHandle->drawBuffer, size.dwSize.X, size.dwSize.Y);
clearTGDrawBuffer(&tgHandle->drawBuffer);
COORD bufferNewSize = {
size.dwSize.X,
size.dwSize.Y
};
return SetConsoleScreenBufferSize(&tgHandle->screenBufferHandle, bufferNewSize);
}
}
test.c
#include "tg.h"
#include <time.h>
#include <stdio.h>
void getMessageAsStr(char *buf) {
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), 0,
buf, 256, NULL);
}
int main() {
// Error buffer
char buf[256];
// Create a drawing context to the screen
struct TGHandle context = TG();
useTGHandle(&context);
setTGHandleCursorVisibility(&context, 0); // Hide the cursor of course
struct TGDrawBuffer *buffer = &context.drawBuffer;
// Create a CHAR_INFO to draw with
CHAR_INFO info;
info.Attributes = BACKGROUND_BLUE | FOREGROUND_WHITE;
info.Char.AsciiChar = ' ';
info.Char.UnicodeChar = ' ';
INPUT_RECORD input;
const int STRING_BUF_SIZE = 64;
char *fpsCountBuffer = malloc(sizeof(char) * STRING_BUF_SIZE);
long start, end;
start = QueryPerformanceCounter(&start);
int running = 1;
while (running) {
// Start off with a nice clean slate
//clearTGDrawBuffer(buffer);
// Collect input to react to resize
while (getTGNextInput(&context, &input)) {
if (input.EventType == WINDOW_BUFFER_SIZE_EVENT) {
if (!TGHandleResizeEvent(&context, input)) {
OutputDebugString("Couldn't resize:\n");
getMessageAsStr(buf);
OutputDebugString(buf);
}
}
}
// Draw line along top and bottom
int i = 0;
while (i < buffer->size.X) {
TGDrawPixel(buffer, i, 0, info);
TGDrawPixel(buffer, i, buffer->size.Y - 1, info);
i++;
}
i = 0;
// Draw vertical lines
while (i < buffer->size.Y) {
TGDrawPixel(buffer, 0, i, info);
TGDrawPixel(buffer, buffer->size.X - 1, i, info);
i++;
}
// FPS count!
// Get time elapsed in millis
QueryPerformanceCounter(&end);
long fps = 1000000 / (end - start);
// Put it into the screen buffer
snprintf(fpsCountBuffer, STRING_BUF_SIZE, "Running at %ldhz, %dx%d", fps, buffer->size.X, buffer->size.Y);
TGDrawString(buffer, 1, 1, fpsCountBuffer, strlen(fpsCountBuffer));
start = end;
updateTGHandle(&context);
}
}
Spotted it right after I posted it. You can see that I'm taking the pointer location of the handle in TGHandleResizeEvent:
return SetConsoleScreenBufferSize(&tgHandle->screenBufferHandle, bufferNewSize);
This is, in fact, an invalid handle. Corrected code:
return SetConsoleScreenBufferSize(tgHandle->screenBufferHandle, bufferNewSize);

How return dynamic massive C

Why my way is doesnt work? "message" refers to Null
first function :
void messageToBit(FILE *m,char *message )
{
int fileSize = 0;
int k = 0;
char symb;
fseek(m, 0, SEEK_END);
fileSize = ftell(m);
fseek(m, 0, SEEK_SET);
message = (char*)malloc(8 * fileSize);
/* some action with message */
}
and call
void gg()
{
char* message = 0;
messageToBit(m, message);
....
}
why not pointing to the correct memory location?
The point is that you should pass a pointer to pointer as a parameter in order to get output value this way. It might be confusing for beginners so instead you can achieve the same result by returning a pointer:
char* messageToBit(FILE *m)
{
int fileSize = 0;
int k = 0;
char* message;
char symb;
fseek(m, 0, SEEK_END);
fileSize = ftell(m);
fseek(m, 0, SEEK_SET);
message = malloc(8 * fileSize); // as mentioned in comments, no cast
/* some action with message */
return message;
}
void gg()
{
char* message = messageToBit(m);
....
}
You need to understand, pass-by-value and pass-by-reference. Change the code to
first function :
void messageToBit(FILE *m,char **message )
{
int fileSize = 0;
int k = 0;
char symb;
fseek(m, 0, SEEK_END);
fileSize = ftell(m);
fseek(m, 0, SEEK_SET);
*message = (char*)malloc(8 * fileSize);
/* some action with message */
}
and call
void gg()
{
char* message = 0;
messageToBit(m, &message);
....
}

Create MPI type for struct containing dynamic array

I'm trying to send a struct which has one of the member as a dynamic array, but this array doesn't seem to be sent properly. Any suggestion on how to do this?
This is what I have:
struct bar
{
int a;
int b;
int* c;
};
void defineMPIType(MPI_Datatype* newType, int cLen, struct bar* msg)
{
int blockLengths[3] = {1, 1, cLen};
MPI_Datatype types[3] = {MPI_INT, MPI_INT, MPI_INT};
MPI_Aint offsets[3];
MPI_Aint addrB, addrC;
MPI_Address(&(msg->b), &addrB);
MPI_Address(msg->c, &addrC);
offsets[0] = offsetof(struct bar, a);
offsets[1] = offsetof(struct bar, b);
offsets[2] = addrC - addrB;
MPI_Type_create_struct(3, blockLengths, offsets, types, newType);
MPI_Type_commit(newType);
}
void main(int argc, char* argv[])
{
MPI_Init(&argc, &argv);
int rank, p;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &p);
int cLen = argv[0];
MPI_Datatype MPI_BAR_TYPE;
struct bar* msg = malloc(sizeof(*msg));
msg->c = malloc(sizeof(int) * cLen);
defineMPIType(&MPI_BAR_TYPE, cLen, msg);
if (rank == 0)
{
msg->a = 1;
msg->b = 2;
for (int i = 0; i < cLen; ++i)
msg->c[i] = i;
MPI_Send(msg, 1, MPI_BAR_TYPE, 1, 111, MPI_COMM_WORLD);
}
else
{
MPI_Status stat;
MPI_Recv(msg, 1, MPI_BAR_TYPE, 0, 111, MPI_COMM_WORLD, &stat);
}
printf("Rank %d has c = [", rank);
for (int i = 0; i < cLen; ++i)
printf("%d, ", msg->c[i]);
printf("]\n");
free(msg);
MPI_Type_free(&MPI_BAR_TYPE);
MPI_Finalize();
}
Members a and b got sent properly, but c didn't.
There are a few issues in your code, even ignoring the issue of the type itself:
The first one is that you allocated memory for your c array only on process #0, then you (tried to) send this data to process #1. But process #1 didn't allocate any memory for storing the message. So even if the way the sending is done was correct, the code would have failed.
Names starting with MPI_ are reserved for the MPI library so you cannot use them as you wish. You have to find another name for your MPI_BAR_TYPE.
This line puzzles me somewhat: int cLen = argv[0]; I imagine you want to read from the command line the size of the array to allocate, in which case maybe that should read something like int clen = atoi(argv[1]); (forgetting about test for validity of this which would need to be properly handled...)
You only test if the process is of rank #0 or not, meaning that if for some reason you launched 3 processes, the process of rank #2 will wait forever for a message from process of rank #0 that will never arrive.
And finally the array itself: in your code there is a big confusion between the pointer c and the data pointed to by c. Your structure embeds the pointer, but not the memory pointed to. So you cannot map into an MPI structure the corresponding data... The most obvious reason is that from one call to the next (or from one process to the next), there is no guaranty that the offset from the address of the structure and the address of the data pointed to by c will be identical (and indeed, it is almost guaranteed it will be different). So you cannot reliably map them.
What you need to do for solving your problem is therefore to only transfer your 2 integers a and b in one go (possibly creating a MPI structure for transferring arrays of them if needed). Then you will transfer the memory pointed by c, which you would have allocated beforehand.
Your code could become for example:
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
struct bar
{
int a;
int b;
int* c;
};
void defineMPIType( MPI_Datatype* newType ) {
struct bar tmp[2];
MPI_Aint extent = &tmp[1] - &tmp[0];
MPI_Type_create_resized( MPI_2INT, 0, extent, newType );
MPI_Type_commit( newType );
}
int main( int argc, char* argv[] ) {
MPI_Init(&argc, &argv);
int rank, p;
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
MPI_Comm_size( MPI_COMM_WORLD, &p );
int cLen = atoi( argv[1] );
MPI_Datatype Bar_type;
defineMPIType( &Bar_type );
struct bar msg;
msg.c = ( int* ) malloc( sizeof( int ) * cLen );
if ( rank == 0 ) {
msg.a = 1;
msg.b = 2;
for ( int i = 0; i < cLen; ++i ) {
msg.c[i] = i;
}
MPI_Send( &msg, 1, Bar_type, 1, 111, MPI_COMM_WORLD );
MPI_Send( msg.c, cLen, MPI_INT, 1, 222, MPI_COMM_WORLD );
}
else if ( rank == 1 ) {
MPI_Recv( &msg, 1, Bar_type, 0, 111, MPI_COMM_WORLD, MPI_STATUS_IGNORE );
MPI_Recv( msg.c, cLen, MPI_INT, 0, 222, MPI_COMM_WORLD, MPI_STATUS_IGNORE );
}
printf("Rank %d has a = %d, b = %d, c = [", rank, msg.a, msg.b );
for ( int i = 0; i < cLen - 1; ++i ) {
printf( "%d, ", msg.c[i] );
}
printf( "%d]\n", msg.c[cLen - 1] );
free( msg.c );
MPI_Type_free( &Bar_type );
MPI_Finalize();
return 0;
}
Which gives:
$ mpirun -n 2 ./a.out 3
Rank 0 has a = 1, b = 2, c = [0, 1, 2]
Rank 1 has a = 1, b = 2, c = [0, 1, 2]
Happy MPI coding.

Mpi_allgather and mpi_pack in C

i have a probelm with mpi and MPI_Allgather and MPI_pack.
I have structure :
typedef struct{
float a;
int b;
int c[];
}struc_t;
I intialize my structure :
struc_t* test=(struc_t*)malloc(sizeof(struc_t)+200*sizeof(int));
And i would like send a array of my structure with MPI_Allgather :
int sizeSend,sizeRcv;
char *bufferSend,*bufferRecv;
int positionSend,PositionRecv;
MPI_Pack_size(10, MPI_MYTYPE , MPI_COMM_WORLD , &sizeSend);
MPI_Pack_size(10*nbProc, MPI_MYTYPE , MPI_COMM_WORLD , &sizeRcv);
MPI_Status statut;
The code of MPI_MYTYPE:
MPI_Aint offsets[3],extent;
int blockcounts[3];
MPI_Datatype oldtypes[3];
MPI_Datatype TAB;
MPI_Type_contiguous(nb,MPI_INT,&TAB);
MPI_Type_commit(&TAB);
offsets[0]=0;
oldtypes[0] = MPI_FLOAT;
blockcounts[0] = 1;
MPI_Type_extent(MPI_FLOAT, &extent);
offsets[1]=extent;
oldtypes[1] = MPI_INT;
blockcounts[1] = 1;
MPI_Type_extent(MPI_INT, &extent);
offsets[2]=extent + offsets[1];
oldtypes[2] = TAB;
blockcounts[2] =1;
MPI_Type_struct(3, blockcounts, offsets, oldtypes, dptr);
MPI_Type_commit(MPI_MYTYPE);
I create my pack :
positionSend=0;
positionRcv=0;
bufferSend = (char*) malloc(sizeSend);
bufferRecv = (char*) malloc(sizeRcv);
for(i=0;i<10;i++){
struc_t *elm = getElement(i);
MPI_Pack(&elm->a,1,MPI_FLOAT,bufferSend,sizeSend,&positionSend,MPI_COMM_WORLD);
MPI_Pack(&elm->b,1,MPI_INT,bufferSend,sizeSend,&positionSend,MPI_COMM_WORLD);
MPI_Pack(elm->c,200,MPI_INT,bufferSend,sizeSend,&positionSend,MPI_COMM_WORLD);
}
and the reception :
MPI_Allgather(bufferSend,1, MPI_PACKED, bufferRecv,1,MPI_PACKED, MPI_COMM_WORLD);
for(i=0;i<10*nbProc;i++){
struc_t* recvStruc=(struc_t*)malloc(sizeof(struc_t)+200*sizeof(int));
MPI_Unpack(bufferRecv, sizeRcv, &positionRcv,&recvStruc->a,1, MPI_FLOAT,MPI_COMM_WORLD);
MPI_Unpack(bufferRecv, sizeRcv, &positionRcv,&recvStruc->b,1, MPI_INT,MPI_COMM_WORLD);
MPI_Unpack(bufferRecv, sizeRcv, &positionRcv,recvStruc->c,200, MPI_INT,MPI_COMM_WORLD);
}
But the resultat of recvStruc is 0 :( where is the problem? If you help me, I call you god lol.
thx
Why pack your structs? It might make sense if they were variable length, but here you are transmitting the 200 integers anyway. A better solution is to just use the MPI datatypes. That way you have a chance of avoiding memory copies, and if the MPI library does need to pack your data behind the scenes, it can do it automatically.
Here's a working example:
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
typedef struct{
float a;
int b;
int c[];
} struc_t;
int main (int argc, char **argv)
{
MPI_Init(&argc, &argv);
int nproc;
MPI_Comm_size(MPI_COMM_WORLD, &nproc);
struc_t *test;
MPI_Aint struc_t_size;
MPI_Datatype struc_t_type;
{
int blocklen[] = {1, 1, 200};
MPI_Aint addr[4];
MPI_Address(test, &addr[0]);
MPI_Address(&test->a, &addr[1]);
MPI_Address(&test->b, &addr[2]);
MPI_Address(&test->c, &addr[3]);
MPI_Aint disp[] = { addr[1] - addr[0],
addr[2] - addr[0],
addr[3] - addr[0] };
MPI_Datatype types[] = {MPI_FLOAT, MPI_INT, MPI_INT};
MPI_Type_create_struct(3, blocklen, disp, types, &struc_t_type);
MPI_Type_commit(&struc_t_type);
}
MPI_Type_extent(struc_t_type, &struc_t_size);
test = malloc(struc_t_size);
// Put our rank in b to verify operation
MPI_Comm_rank(MPI_COMM_WORLD, &test->b);
void *buf = malloc(struc_t_size * nproc);
MPI_Allgather(test, 1, struc_t_type, buf, 1, struc_t_type, MPI_COMM_WORLD);
MPI_Type_free(&struc_t_type);
{
int i;
struc_t *p;
// Verify that everything was received correctly
for (i = 0; i < nproc; i++) {
p = buf + struc_t_size * i;
printf("%d %d\n", i, p->b);
}
}
MPI_Finalize();
return 0;
}

Resources