#c #mpi
#c #mpi
Вопрос:
У меня есть код MPI, в котором процессы считывают двоичный файл и записывают его обратно. Способ распределения данных заключается в том, что процесс 0 считывает (а затем записывает) первую половину файла, тогда как процесс 1 считывает (а затем записывает) вторую половину файла. Проблема здесь в том, что входные и выходные файлы не совпадают (diff показывает, что они отличаются). Если есть только 1 процесс, все работает нормально. Может кто-нибудь указать, что происходит не так?
Используя OpenMPI, скомпилированный как: mpicc -Wall test_mpi.c -o test_mpi
Выполняется как: mpirun -np 2 ./test_mpi
Заранее спасибо.
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
int main(int argc, char** argv) {
int rank, np, i; //np = no. of processes
MPI_Init(amp;argc, amp;argv);
MPI_Comm_rank(MPI_COMM_WORLD, amp;rank);
MPI_Comm_size(MPI_COMM_WORLD, amp;np);
int filesize = 48*1048576; //input filesize 48MB
double *data = (double*) malloc (filesize/np);
FILE* fpa;
fpa = fopen ( "512_featurevec.out", "rb");
fseek(fpa, filesize/np*rank, SEEK_SET);
printf("read: %dn", (int)fread(amp;data[0], sizeof(double), filesize/(np*sizeof(double)), fpa));
fclose(fpa);
char* outfile = "outfile.txt";
for(i=0; i<np; i ) {
if(rank == i) {
fpa = fopen ( outfile, "ab");
fseek(fpa, filesize/np*rank, SEEK_SET);
fwrite ( amp;data[0], sizeof(double), filesize/(np*sizeof(double)), fpa);
fclose ( fpa );
}
}
free(data);
MPI_Finalize();
exit(0);
}
Комментарии:
1. Пожалуйста, не приводите указатель, возвращаемый malloc() . Вам вообще не нужно его трогать, и, если вы это сделаете, вы можете допустить ошибки.
Ответ №1:
Похоже, проблема связана с тем, что каждый дочерний элемент открывает файл для записи, что приводит к конфликту.
Попробуйте, чтобы имя файла зависело от ранга (например, запись в out file.txt.(rank)
и посмотрите, совпадают ли все выходные данные.
Комментарии:
1. Спасибо за этот пост, я ломал голову, не добиваясь никакого прогресса, пока не прочитал этот пост. Так просто.
Ответ №2:
Если вы уже используете MPI и сталкиваетесь с проблемой использования seek для разделения файла, вместо использования POSIX я бы предложил использовать MPI-IO (стандарт как часть MPI2, c. 1996 или около того): Хорошие ссылки:
- http://www.mhpcc.edu/training/workshop2/mpi_io/MAIN.html
- http://beige.ucs.indiana.edu/B673/node179.html
и в нашем центре у нас есть первая часть этого, которая, я думаю, довольно хороша:
Версия вашего кода с поддержкой MPI, приведенная выше, такова:
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
int main(int argc, char** argv) {
int rank, np;
MPI_Init(amp;argc, amp;argv);
MPI_Comm_rank(MPI_COMM_WORLD, amp;rank);
MPI_Comm_size(MPI_COMM_WORLD, amp;np);
const int filesize = 48*1048576; //input filesize 48MB
const int ndoubles = filesize/(sizeof(double)*np);
double *localdata = malloc(ndoubles*sizeof(double));
/* create a type which describes our view of the file --
* in particular, just our subarray of the global array
*/
int globalsizes[1] = {filesize};
int localsizes[1] = {ndoubles};
int starts[1] = {ndoubles*rank};
MPI_Datatype fileview;
MPI_Type_create_subarray(1, globalsizes, localsizes, starts, MPI_ORDER_C, MPI_DOUBLE, amp;fileview);
MPI_Type_commit(amp;fileview);
/* read in only our data */
MPI_File fpa;
MPI_Status status;
MPI_File_open(MPI_COMM_WORLD, "512_featurevec.out", MPI_MODE_RDONLY, MPI_INFO_NULL, amp;fpa);
/* note could use MPI_File_seek instead of file set view */
MPI_File_set_view(fpa, (MPI_Offset)0, MPI_DOUBLE, fileview, "native", MPI_INFO_NULL);
MPI_File_read_all(fpa, localdata, ndoubles, MPI_DOUBLE, amp;status);
MPI_File_close(amp;fpa);
/* write out data - it will have same layout, we're just writing instead of erading*/
MPI_File_open(MPI_COMM_WORLD, "output.dat", MPI_MODE_WRONLY|MPI_MODE_CREATE, MPI_INFO_NULL, amp;fpa);
/* note could use MPI_File_seek instead of file set view */
MPI_File_set_view(fpa, (MPI_Offset)0, MPI_DOUBLE, fileview, "native", MPI_INFO_NULL);
MPI_File_write_all(fpa, localdata, ndoubles, MPI_DOUBLE, amp;status);
MPI_File_close(amp;fpa);
free(localdata);
MPI_Type_free(amp;fileview);
MPI_Finalize();
return 0;
}
Комментарии:
1. Я быстро захотел измерить ускорение ввода-вывода, поэтому я попытался распараллелить fwrite, как я показал. Но я согласен, MPI_IO определенно лучший способ.
2. Вы можете использовать MPI_File_seek (или MPI_File_write_at) очень похожим образом на то, что у вас уже есть, и у него будет лучшая семантика (например, не будет странно действовать, если кто-то другой переместит указатель на файл …)
Ответ №3:
Отвечая на мой собственный вопрос, но это работает:
char* outfile = "outfile.txt";
for(i=0; i<np; i ) {
if(rank == i) {
fpa = fopen ( outfile, "ab");
fseek(fpa, filesize/np*rank, SEEK_SET);
fwrite ( amp;data[0], sizeof(double), filesize/(np*sizeof(double)), fpa);
fclose ( fpa );
}
MPI_Barrier(comm);
}
По какой-то причине, если proc 1 прибывает перед proc 0 и fseeks пустой файл с некоторым значением, он помещает указатель файла на правильное смещение (проверено ftell), но записывает только со смещения 0. (Должно быть, я делаю что-то тривиально неправильное, но в любом случае).