【问题标题】:Speed Tradeoff: Frequently Reading from file vs storing it using dynamic memory速度权衡:经常从文件读取与使用动态内存存储它
【发布时间】:2011-07-26 07:25:01
【问题描述】:

我正在编写一个 C 程序,该程序涉及读取图像文件并仅读取图像的每个像素一次。那么我应该使用 fread() 读取文件一次并将其存储在一些动态变量(堆变量)中还是经常为每个像素使用 fread()? 图像的大小为 1000*1000 到 5000*5000。 我将在 MPI 和 CUDA 中扩展相同的程序。我将不胜感激任何其他建议。 谢谢。

【问题讨论】:

  • 一次读取一个像素肯定会很慢,但如果您的计算已经非常昂贵,即使这样也可能不会引起注意。但是,这并不意味着您需要将整个文件读入内存。您可以轻松使用内存映射文件 (mmap) 或一次只读取合理大小的块(4-16k 应该足以弥补读取的开销成本)。

标签: c image cuda file-handling


【解决方案1】:

即使是 12 位彩色 ARGB 图像也需要大约 150 MB 才能获得 5,000 * 5,000 像素的分辨率,这完全在当前所有 PC 甚至许多 GPU 卡的能力范围内。如果你有这种可用的内存,你应该在动态分配的数组中读取一次,或者类似的东西。它将允许您以大 I/O 块读取整个图像,速度更快,并使用直接内存操作 (img[1234][4321][RED] = 34),而不是使用 I/O 函数使您的代码复杂化。

如果您没有这种可用内存,请查看mmap() 或您的操作系统存在的任何等效项,以将文件映射到虚拟内存。您仍然拥有使用直接内存操作的优势,而不必将整个内容加载到内存中,尽管计算成本会更高。

也就是说,现代操作系统执行广泛的数据缓存和预取,因此使用fread() 可能不会那么慢。此外,在当前具有 glibc-2.3 或更高版本的 Linux 系统上,可以选择使用 mmap() 进行文件访问,即使应用程序使用标准 stdio 函数执行 I/O。

【讨论】:

    【解决方案2】:

    取决于您需要处理哪种算法。 5000 * 5000 的图像约为 95 Mb。没什么大不了的。

    在 Gpu 方面,您可以异步上传到 GPU 内存,以大约 4MB-16MB 的块来饱和带宽

    #pseudocode:
    
     for chunk in fread(4096MB):
         gpu.uploadAsync (chunk) # will not block
     gpu.execute() #wait that all the previous memory transfers are completed.
    

    您必须在 cuda 上使用固定内存,我认为如果您使用内存映射文件复制块 会更快。

    像往常一样配置您的应用程序以获得最佳调整。

    【讨论】:

      【解决方案3】:

      我打算把它写下来作为评论,但它变得太长了。但切入正题……

      我同意 T.E.D.和乔纳森·伍德:

      一般来说,我找到了最快的方法 处理文件就是尝试阅读 整个事情在一个大的记忆中 I/O,并在内存不足时处理它 从那时起。它经常使 代码也更简单。

      -T.E.D

      这取决于。你应该尝试 估计大部分的内存量 将运行您的软件的计算机。 这还取决于速度有多关键 你的代码是。

      显然,一种方法更快 而另一个使用更多的内存。 一般来说,你可能没问题 在大多数现代设备上将其加载到内存中 电脑,这更容易。但是你 必须权衡利弊 你的特殊情况

      -乔纳森·伍德

      请记住,32 位颜色的 5000*5000 像素占用大约 100 兆字节的内存(+ 可能有一些开销,以及您的软件需要的任何其他内容)。我会说(最好的猜测 Stetson-Harrison 值)大多数现代台式计算机至少有 1 或 2 GB 内存(我的内存是 2008 年购买的,有 4 个),所以即使整个东西都加载了,也没有那么多同时,笔记本电脑的内存可能会更少。

      CUDA 方面也很有趣(我对 CUDA 几乎一无所知),数据是否加载到 GPU 的内存中?支持 CUDA 的 GPU 通常有多少内存? PCI-e 总线会不会成为瓶颈(可能不会……?)?了解支持 CUDA 的常见 CUDA-enabled 台式机和笔记本电脑 GPU 有多少内存。

      一种妥协可能是尝试缓冲读取,让另一个线程“预读”文件中的数据,而其他线程处理(并在执行过程中释放内存)数据。

      【讨论】:

        【解决方案4】:

        还有一个问题可以帮助您做出决定:How exactly does fopen(), fclose() work?

        如果您正在寻找速度,最好将整个文件一次加载到内存中并在那里进行操作。这样,您就可以避免不必要地调用您的硬盘驱动程序来提供数据。当您开始谈论为 5k 图像提供 25,000,000 个不同的 4 字节块(假设为 32 位 RGBA)时,您可能会看到大量的查找、读取和等待。

        这是经典的内存与速度权衡之一。如果您的客户有足够的内存,那么最好将所有数据加载到内存中,然后执行转换。

        否则尝试一次加载足够多的数据(分页),以使其快速并适合您的目标内存配置文件。

        【讨论】:

          【解决方案5】:

          通常我发现处理文件的最快方法是尝试在一次大 I/O 中将整个内容读入内存,然后从内存中处理它。这通常会使代码更简单也。

          您当然必须担心文件可能不适合任何可用的连续内存块。如果您处理得当(而不仅仅是保释),代码会变得更加复杂。作为一名经过认证的懒惰程序员,如果我能侥幸逃脱,我宁愿选择保释。 :-)

          【讨论】:

            【解决方案6】:

            将其存储在内存中肯定会更快。如果您每次都从硬盘读取小块,由于访问时间最短等原因,您总是会遇到延迟。

            【讨论】:

              【解决方案7】:

              这取决于。您应该尝试估计将运行您的软件的大多数计算机上的内存量。这还取决于您的代码对速度的要求。

              显然,一种方法速度更快,而另一种方法使用更多内存。一般来说,您可能可以在大多数现代计算机上将其加载到内存中,这更容易。但是你必须权衡你的具体情况的利弊。

              【讨论】:

                【解决方案8】:

                看看在windows下使用mmap() linux或者mapviewofile()。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2013-04-28
                  • 2013-05-17
                  • 2020-09-13
                  • 1970-01-01
                  相关资源
                  最近更新 更多