将文件读取到共享内存中

3
我正在阅读一个二进制文件,我希望通过Cilk和共享内存直接将其卸载到Xeon Phi上。
由于我们一次读取相当多的数据,并且二进制数据是首选选项,因此最好使用fread。
因此,如果我制作一个非常简单的示例,它会像这样:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

_Cilk_shared uint8_t* _Cilk_shared buf;

int main(int argc, char **argv) {
  printf("Argv is %s\n", argv[1]);
  FILE* infile = fopen(argv[1], "rb");
  buf = (_Cilk_shared uint8_t*) _Offload_shared_malloc(2073600);
  int len = fread(buf, 1, 2073600, infile);
  if(ferror(infile)) {
    perror("ferror");
  }
  printf("Len is %d and first value of buf is %d\n", len, *buf);
  return 0;
}

这个例子是从真实代码简化而来的,但足以说明行为。
然后,此代码将返回
ferror: Bad address
Len is 0 and first value of buf is 0

然而,如果我们将fread替换为fgets(对于读取二进制数据而言并不是非常适合,特别是返回值方面),那么事情就会变得很好。也就是说,我们将fgets((char*)buf,2073600,infile)进行切换,然后从输出中删除len,我们可以得到buf的第一个值为46,这符合我们的要求,我可以在具有buf作为参数的函数上运行_Offload_cilk并对其进行处理。
我是否遗漏了什么或者fread是否不受支持?我已经尝试从英特尔和其他互联网站点找到尽可能多的信息,但遗憾的是我没有找到。
----编辑----
在更深入地研究后,似乎在共享内存上运行fread时,如果值大于524287(524287恰好是19位),则会出现上述错误。 在524287或更低的值下,一切正常,您可以运行任意数量的fread并读取所有数据。
我完全找不到任何原因写在任何地方。
2个回答

2

我没有 PHI,所以无法确定这是否会有所不同 -- 但 fread 有自己的缓冲区,虽然可能被关闭以进行此类型的读取,但我不明白为什么您要使用 fread 而不是直接使用 open&read 的低级调用,如:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdint.h>

_Cilk_shared uint8_t* _Cilk_shared buf;

int main(int argc, char **argv) {
  printf("Argv is %s\n", argv[1]);
  int infile = open(argv[1], O_RDONLY); // should test if open ok, but skip to make code similar to OP's
  int len, pos =0, size = 2073600;
  buf = (_Cilk_shared uint8_t*) _Offload_shared_malloc(size);
  do { 
      buf[pos]=0; // force the address to be mapped to process memory before read
      len = read(infile, &buf[pos], size);
      if(len < 0) {
         perror("error");
         break;
      }
      pos += len; // move position forward in cases where we have no read the entire data in first read.
      size -= len;
  } while (size > 0);
  printf("Len is %d (%d) and first value of buf is %d\n", len, pos, *buf);
  return 0;
}

读写共享内存时,应该毫无问题地使用分配的内存。


好主意,因为它可能是缓冲区的问题。但不幸的是,它返回与fread代码相同的结果,带有错误地址。 - Asthor
不知何故地址段未映射到您的进程内存空间——我猜测_Offload_shared_malloc使用某种延迟评估,那么尝试通过在第一个地址写入单个字节(例如,在read之前写入 *buf = 0;)来强制映射到进程空间,怎么样? - Soren
是的。这与上面的答案中的理论相符。read()函数并没有读取全部2073600字节,而只读取了1048568字节。fread()函数也可以工作,并且读取了相同数量的字节。这可能更多地涉及到它所做的整个惰性分配。 - Asthor
只需循环和读取--读取调用不能保证给你想要的,而在套接字编程中,循环和聚合数据是很常见的--当读取调用返回-1时,查看errno中的特定错误代码以查看是否可以重试某些操作,然后放弃--我编辑了一个最小的循环结构的代码,应该适合你。 - Soren
是的,已经在循环了。更感兴趣的是理解实际分配的原因。感谢您的编辑,但是代码片段只是问题的一个快速示例。实际代码要复杂得多。 - Asthor

1

你能在fread调用之前尝试插入类似这样的内容吗?

memset(buf, 0, 2073600); // after including string.h

这个技巧对我有用,但我不知道为什么(惰性分配?)。
顺便说一下,你也可以在这个论坛上发布一个MIC问题。

没错,那个可行。我猜你对于惰性分配是正确的,急切分配也没有太多意义。不过很遗憾找不到相关文档,这会很有帮助。 - Asthor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接