I / O执行速度比一次读取一点点慢

时间:2011-01-20 01:09:00

标签: c++ optimization cuda gpgpu

我正在研究我们准备使用cuda在GPU上进行优化和算法。

I / O部分从3个不同的图像读入,一次一行。这正好在循环的中间,用于在图像上运行过滤器。我决定尝试通过将I / O移除到自己的循环来预加载正在生成的值,并将值转储到保存图像的数组中,并用于计算。

现在,问题是,似乎我的应用程序在缓冲区完全加载数据的情况下运行速度较慢,并且在每次迭代都必须转出磁盘以获取新数据时速度更快。

可能导致这种情况的原因是什么?来自较大缓冲区的缓存丢失是否真的会对性能造成太大影响?这不是内存问题 - 在这台机器上有24GB的内存,它有很多内存。

不确定它可能是什么,愿意听取意见

3 个答案:

答案 0 :(得分:2)

@Derek提供了以下附加信息:

  

(运行时间)......“超过一分钟,相比之下   10-14秒之前。我不是在做   任何特定的线程,虽然我这样做   有一些OpenMP pragma。移动   过滤器循环外的I / O没有   改变其中任何一个。我是   运行CentOS 5.5。图像大小是   约72MB“

这是运行时间巨大的差异。由于使用了OpenMP,我们可以假设有多个线程。由于您只处理72MB的数据,我无法看到I / O时间差异如何之大。我们可以肯定读取时间小于原来的10-14秒,所以除非你在代码的那部分有一个错误,否则额外的时间在过滤器部分。图像大概是二进制的吗?由于@Satya建议对您的代码进行分析,或者至少添加一些时间打印输出可能有助于确定问题所在。

循环阅读的“优势”可能是:

  1. 操作系统为您提供了一些并行性,因为它能够与您的计算并行执行某些I / O,例如:提前阅读。当你提前阅读所有内容时,你会失去这种并行性,在阅读时会有效阻止。
  2. 在您的过滤器访问数据时,读取的数据位于缓存中。如果处理相对于内存带宽是轻量级的,则高速缓存未命中确实会破坏性能。很难相信这会在这个用例中产生显着差异,因为磁盘I / O比内存慢得多。
  3. 鉴于您的最新更新,我们似乎更有可能处理#2。值得注意的是内存访问模式(包括所有线程),您可能会看到缓存抖动,因为主内存中相邻的数据现在更加分散。这可能会产生很大的影响,因为如果您有许多内存访问并且它们都是缓存未命中,那么您总是会产生进一步访问数据的成本,这可能是一个数量级的差异。

    解决这个问题的方法是将你的记忆安排在条纹中,例如:来自第一图像的n行,接着来自第二图像的n行,接着来自第三图像的n行。 IIRC这种技术被称为“条带化”。确切的条带大小取决于您的CPU,但是您可以尝试(或者从内部循环中读取的相同数量的数据开始,如果它足够大)。

    E.g:

    stripe_number = 0;
    do
    {
        count = fread(striped_buffer+(STRIPE_SIZE*stripe_number*NUM_IMAGES), 1, STRIPE_SIZE, image_file);
        stripe_number++;
    } while(count != 0);
    

    一次读取一个文件,这样您就不会在驱动器上来回寻找。

    无论如何,为了最大限度地提高性能,您可能需要研究使用异步/重叠I / O,以便在处理前一位时使用下一位图像数据。

    如果您在Windows下进行开发,这可以帮助您开始重叠I / O: http://msdn.microsoft.com/en-us/library/ms686358%28v=vs.85%29.aspx

    一旦您并行执行I / O,您就可以确定您的瓶颈是在I / O中还是在处理中。有不同的技术来优化它们。

答案 1 :(得分:0)

是的,您将图像加载到L2缓存两次 - 从文件加载然后从内存加载。您还必须花一些时间将数据从缓存移动到内存中。

作为一个选项,您可以尝试加载一些部分,如2-8Mb(取决于您的L2缓存大小)

答案 2 :(得分:0)

除了@Guy:回答,我应该提一下内存映射文件,它们是两种方法中最好的部分。但是,要花费大约一秒钟读取70Mb,问题就在于其他地方。

这可能是由核心缓存的一致性引起的。我对此知之甚少,但如果两个线程同时具有对同一内存页面的写访问权(或者更糟糕的是,对同一缓存行),则必须同步它们的缓存。当您一次读取整个图像时,所有处理线程将同时处理它们。他们会用紧密的内存地址写出结果吗?如果您逐行读取图像,它们将花费一些时间等待I / O完成,因此不会经常发生。