【问题标题】:File read issues - Parallel version of Game of Life文件读取问题 - Game of Life 的并行版本
【发布时间】:2015-05-07 13:44:19
【问题描述】:

对于我的并行计算课程,我正在研究一个使用 MPI 并行化生命游戏的项目。我正在执行 Michael J. Quinn 的“使用 MPI 和 OpenMP 进行 C 并行编程”中的练习 6.13。

我正在使用作者预先编写的库函数“read_row_striped_matrix”。下面是函数的代码:

/*
 *   Process p-1 opens a file and inputs a two-dimensional
 *   matrix, reading and distributing blocks of rows to the
 *   other processes.
 */

void read_row_striped_matrix (
   char        *s,        /* IN - File name */
   void      ***subs,     /* OUT - 2D submatrix indices */
   void       **storage,  /* OUT - Submatrix stored here */
   MPI_Datatype dtype,    /* IN - Matrix element type */
   int         *m,        /* OUT - Matrix rows */
   int         *n,        /* OUT - Matrix cols */
   MPI_Comm     comm)     /* IN - Communicator */
{
   int          datum_size;   /* Size of matrix element */
   int          i;
   int          id;           /* Process rank */
   FILE        *infileptr;    /* Input file pointer */
   int          local_rows;   /* Rows on this proc */
   void       **lptr;         /* Pointer into 'subs' */
   int          p;            /* Number of processes */
   void        *rptr;         /* Pointer into 'storage' */
   MPI_Status   status;       /* Result of receive */
   int          x;            /* Result of read */

   MPI_Comm_size (comm, &p);
   MPI_Comm_rank (comm, &id);
   datum_size = get_size (dtype);

   /* Process p-1 opens file, reads size of matrix,
      and broadcasts matrix dimensions to other procs */

   if (id == (p-1)) {
      infileptr = fopen (s, "r");
      if (infileptr == NULL) *m = 0;
      else {
         fread (m, sizeof(int), 1, infileptr);
         fread (n, sizeof(int), 1, infileptr);
      }      
   }
   MPI_Bcast (m, 1, MPI_INT, p-1, comm);

   if (!(*m)) MPI_Abort (MPI_COMM_WORLD, OPEN_FILE_ERROR);

   MPI_Bcast (n, 1, MPI_INT, p-1, comm);

   local_rows = BLOCK_SIZE(id,p,*m);

   /* Dynamically allocate matrix. Allow double subscripting
      through 'a'. */

   *storage = (void *) my_malloc (id,
       local_rows * *n * datum_size);
   *subs = (void **) my_malloc (id, local_rows * PTR_SIZE);

   lptr = (void *) &(*subs[0]);
   rptr = (void *) *storage;
   for (i = 0; i < local_rows; i++) {
      *(lptr++)= (void *) rptr;
      rptr += *n * datum_size;
   }

   /* Process p-1 reads blocks of rows from file and
      sends each block to the correct destination process.
      The last block it keeps. */

   if (id == (p-1)) {
      for (i = 0; i < p-1; i++) {
         x = fread (*storage, datum_size,
            BLOCK_SIZE(i,p,*m) * *n, infileptr);
         MPI_Send (*storage, BLOCK_SIZE(i,p,*m) * *n, dtype,
            i, DATA_MSG, comm);
      }
      x = fread (*storage, datum_size, local_rows * *n,
         infileptr);
      fclose (infileptr);
   } else
      MPI_Recv (*storage, local_rows * *n, dtype, p-1,
         DATA_MSG, comm, &status);
}

在我的代码开头,我这样称呼“read_row_striped_matrix”:

#include <stdio.h>
#include <mpi.h>
#include "MyMPI.h"

typedef int dtype;
#define MPI_TYPE MPI_INT

int main(int argc, char *argv[]) {

  dtype** matrix;         /* Doubly-subscripted array */
  dtype*  storage;        /* Local portion of array elements */
  int     proc_id;        /* Process Rank */
  int     row_count;      /* Number of rows in matrix */
  int     col_count;      /* Number of columns in matrix */
  int     proc_count;     /* Number of processes */ 
  int     i;              /* Used with for loop */

  MPI_Init                (&argc, &argv);
  MPI_Comm_rank           (MPI_COMM_WORLD, &proc_id);
  MPI_Comm_size           (MPI_COMM_WORLD, &proc_count); 


  read_row_striped_matrix (argv[3], (void *) &matrix, (void *) &storage, MPI_TYPE, 
    &row_count, &col_count, MPI_COMM_WORLD);

  ....

问题是,我的实现陷入了无限循环。所以我通过测试开始调试,看看数据是否从文本文件中正确读取。我的名为“file_input.txt”的文本文件包含以下输入,其中第一个数字(5)表示行数,第二个数字(也是 5)表示列数,其余数据是值在矩阵中:

5 5 0 0 1 0 1 0 0 1 ...

我在从文本文件中读取长度和高度的库代码部分插入了以下 printf 语句:

if (id == (p-1))    
    printf("The name of the file is %s\n", s);
    infileptr = fopen (s, "r");
    if (infileptr == NULL) *m = 0;
    else {
        printf("The value of m is %d\n", *m);

        size_t ret_val      = fread (m, sizeof(int), 1, infileptr);
        size_t next_ret_val = fread (n, sizeof(int), 1, infileptr);

        printf("The total # of elements successfully read is: %d\n", ret_val);
        printf("The total # of elements successfully read is: %d\n", next_ret_val);

        printf("The value of m is %d\n", *m);
        printf("The value of n is %d\n", *n);
   }
}

对于执行“project_3 5 5 file_input.txt”,程序的输出为:

The name of the file is: file_input.txt
The value of m is 0
The total number of elements successfully read is: 1
The total number of elements successfully read is: 1
The value of m is: 540549176
The value of n is: 540090416
...

据我观察,文件名被正确读入,m(0)的值在调用fread之前是正确的。 fread 正在读取 m 和 n 的正确元素数,但值是“540549176”和“540090416”而不是 5 和 5。当我尝试将文本文件开头的数字更改为“3和 4" 为例,m 和 n 的值不变。

有人知道为什么前两个整数没有从文本文件中正确读取吗?提前致谢。

【问题讨论】:

  • 看看这些大数的十六进制表示:“(空格)1(空格)0”和“(空格)8(空格)8”。您正在尝试将 ASCII 文件作为二进制整数读取。
  • 但是在 fopen 调用中,它传递的是“r”,而不是“rb”,所以我认为这确实意味着将文本文件解释为 ASCII,对吧?
  • @SamParsons 否。该标志在 Linux 上被忽略;在 Windows 上,它会转换换行符。您仍然必须从十六进制转换为二进制,反之亦然。
  • 我很抱歉,但我想我在这里误解了一些东西。我会将“540549176”转换为什么?无论我将其转换为什么,它都不等于“5”,即我想从文本文件中读取的值。您是否建议我添加一行代码来解决此问题?

标签: c linux file io mpi


【解决方案1】:

这里有两个选择:

  • 此程序需要二进制输入。所以你需要以某种方式产生二进制输入。 “5”是十六进制值为 0x35(十进制 53)的 ascii 字符。当你 fread sizeof(int) 时,你实际上要输入 2 个字符。

  • 您可以编辑程序以解析 ascii 文本,但这有点烦人。首先读入文件的一行,然后将其标记化,然后将每个标记转换为整数。你来自 perl/python 背景吗?这种文本转换的东西在脚本语言中几乎是自动的。在 C 中没有什么是自动的

【讨论】:

  • 罗布,感谢您的回答。我实际上来自 C++/Java 背景。我创建了一个小型测试程序来尝试从文本文件中读取整数并得到相同的结果。所以我尝试将它们作为字符读取,并且数字被正确读取。因此,我的下一个目标是尝试弄清楚如何像您在第一点中提到的那样生成二进制输入。
  • 看看 rhubarbdog 的回答如下:在文本编辑器中创建二进制文件很困难(但并非不可能),所以用一个小程序创建二进制文件。该程序可以从配置文件或提示用户中获取输入。
  • 谢谢。我只是对这个“read_row_striped_matrix”函数的作者在他的代码中调用 fread 函数并将值保存到整数变量时的意图感到困惑。也许他期望输入文件是二进制文件?他似乎从未在教科书中提及这一点。
  • 肯定需要二进制数据:“fread (m, sizeof(int), 1, infileptr)” 读入(可能)4字节的数据。您无法知道文本编号将包含多少个字符(除非您施加 1 位限制),因此您必须为基于文本的输入文件执行读取和解析操作。
  • 我明白了。再次感谢您的帮助,
【解决方案2】:

看起来你需要去掉库函数并重写它来读取和解释文本文件。目前它读取二进制数据,当它读入 m 和 n 时,它会读取 sizeof(int) (可能是 4 个字节)的十六进制数据,即 00,00,00,05 是文件中的预期值,但前 4 个字节是76,32,76,32 之类的东西 与其重写库函数,不如编写一个文件编译器,将文本文件作为输入读取并将其作为二进制数据写入

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-04-13
    • 2022-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-15
    • 1970-01-01
    相关资源
    最近更新 更多