我正在研究我们准备使用cuda在GPU上进行优化和算法。
I / O部分从3个不同的图像读入,一次一行。这正好在循环的中间,用于在图像上运行过滤器。我决定尝试通过将I / O移除到自己的循环来预加载正在生成的值,并将值转储到保存图像的数组中,并用于计算。
现在,问题是,似乎我的应用程序在缓冲区完全加载数据的情况下运行速度较慢,并且在每次迭代都必须转出磁盘以获取新数据时速度更快。
可能导致这种情况的原因是什么?来自较大缓冲区的缓存丢失是否真的会对性能造成太大影响?这不是内存问题 - 在这台机器上有24GB的内存,它有很多内存。
不确定它可能是什么,愿意听取意见
答案 0 :(得分:2)
@Derek提供了以下附加信息:
(运行时间)......“超过一分钟,相比之下 10-14秒之前。我不是在做 任何特定的线程,虽然我这样做 有一些OpenMP pragma。移动 过滤器循环外的I / O没有 改变其中任何一个。我是 运行CentOS 5.5。图像大小是 约72MB“
这是运行时间巨大的差异。由于使用了OpenMP,我们可以假设有多个线程。由于您只处理72MB的数据,我无法看到I / O时间差异如何之大。我们可以肯定读取时间小于原来的10-14秒,所以除非你在代码的那部分有一个错误,否则额外的时间在过滤器部分。图像大概是二进制的吗?由于@Satya建议对您的代码进行分析,或者至少添加一些时间打印输出可能有助于确定问题所在。
循环阅读的“优势”可能是:
鉴于您的最新更新,我们似乎更有可能处理#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完成,因此不会经常发生。