2012-10-20 36 views
1

我对图像的子区域进行了大量操作。例如,如果我有一个100x100的图像,我可能想迭代这个图像并处理10x10像素的块。例如:显式预取非连续数据

for(each 10x10 block) 
{ 
    for(each pixel in the block) 
    { 
    do something 
    } 
} 

这种方法的问题是,小块不是连续的内存块(即,图像的像素被存储以行优先顺序,所以,当我访问10×10块,每行中的像素的块是连续的,但块的行不是连续的,有什么可以做的,以加速访问这些块中的像素?或者是不可能快速访问数据的一个区域像这样的结构?

从我读过的很多读物中,听起来像是第一次读取像素,因为循环中唯一的操作可能是有用的:

// First read the pixels 
vector<float> vals(numPixels); 
for(pixels in first row) 
{ 
val[i] = pixels[i]; 
} 

// Then do the operations on the pixels 
for(elements of vals) 
{ 
doSomething(vals[i]) 
} 

与我在做什么这是两者同时进行公正:

// Read and operate on the pixels 
for(pixels in first row) 
{ 
doSomething(pixels[i]) 
} 

,但我无法找到任何实际的代码示例(与理论解释)是如何做到这一点。有没有道理呢?

+0

将像素复制到矢量中会将它们放入连续的内存区域,如果它们适合高速缓存线,则通常会对其进行高速缓存。 – chradcliffe

+0

@chradcliffe,但如果他们只使用一次会帮助什么? –

+0

我认为@MvG对此有正确答案。 '__builtin_prefetch'将是正确的使用。我已经忘记了那个内建。它将保存副本并在您仅使用一次值的情况下工作。 – chradcliffe

回答

1

gcc有一个内建功能__builtin_prefetch。您可以将地址传递给该函数,并且在支持该函数的目标上,gcc将发出机器指令,使该地址即使未立即使用,也会将其加载到缓存中。

许多现代图像处理应用商店图像瓷砖,而不是在(又名*扫描线)你描述。例如。 GIMP does that。因此,如果您可以控制图像的存储方式,那么使用平铺方法可能会增加局部性,从而减少缓存未命中并提高性能。

+0

使用扫描线存储系统时,是否必须预取小图像块的每个地址?或者只是行块中每行的第一个像素的地址? –

+0

@DavidDoria,每当你预取一个字节的数据,它的整个缓存行将被加载到缓存中。与图像相关的方式取决于CPU架构,内存对齐等。一般来说,我会假设为每一行预加载第一个像素*就足够了。如果有疑问,请尝试两种方法并对其进行基准测试 – MvG