C++ 非连续数据的显式预取
我对图像的子区域做了很多操作。例如,如果我有一个100x100的图像,我可能想迭代这个图像并处理10x10像素的块。例如:C++ 非连续数据的显式预取,c++,caching,C++,Caching,我对图像的子区域做了很多操作。例如,如果我有一个100x100的图像,我可能想迭代这个图像并处理10x10像素的块。例如: for(each 10x10 block) { for(each pixel in the block) { do something } } 问题是,这些小块不是连续的内存块(即,图像像素按行主顺序存储,因此当我访问10x10块时,块中每一行的像素都是连续的,但块中的行不是连续的。是否可以采取任何措施来加快对这些块中像素的访问速度?还是不可能快速访问
for(each 10x10 block)
{
for(each pixel in the block)
{
do something
}
}
问题是,这些小块不是连续的内存块(即,图像像素按行主顺序存储,因此当我访问10x10块时,块中每一行的像素都是连续的,但块中的行不是连续的。是否可以采取任何措施来加快对这些块中像素的访问速度?还是不可能快速访问数据结构的某个区域你喜欢这样吗
从我做的大量阅读中,它听起来像是第一次读取像素,因为循环中的唯一操作可能有用:
// 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])
}
但我找不到任何实际的代码示例(相对于理论解释)这是真的吗?
gcc
有一个名为的内置函数。您可以将地址传递给该函数,在支持该函数的目标上,gcc
将发出一条机器指令,导致该地址加载到缓存中,即使它没有立即使用
许多现代图像处理应用程序将图像存储在平铺中,而不是存储在行中(又称扫描线)您描述了。例如GIMP。因此,如果您可以控制映像的存储方式,则使用平铺方法可能会增加局部性,从而减少缓存未命中并提高性能。
gcc
有一个内置函数名为。您可以将地址传递给该函数,并且在支持该函数的目标上,gcc
将l发出一条机器指令,导致该地址被加载到缓存中,即使它没有立即被使用
许多现代图像处理应用程序将图像存储在平铺中,而不是存储在行中(又称扫描线)您描述了。例如GIMP。因此,如果您可以控制图像的存储方式,则使用平铺方法可能会增加局部性,从而减少缓存未命中并提高性能。将像素复制到向量中会将其放置到连续的内存区域中,如果它们适合缓存线,则通常会将其缓存。@chradcliffe但是如果它们只使用一次会有帮助吗?我认为@MvG对这个问题的答案是正确的。
\u builtin\u prefetch
将是正确的使用方法。我已经忘记了那个内置的。它将保存副本,并在您只使用一次值的情况下工作。将像素复制到向量中会将它们置为into一个连续的内存区域,如果它们适合缓存线,通常会被缓存。@chradcliffe但是如果它们只被使用一次,那会有什么帮助吗?我认为@MvG对此有正确的答案。\u内置预取
将是正确的使用方法。我已经忘记了那个内置。它将保存副本并在ca中工作请注意,您只使用了一次该值。使用扫描线存储系统,我是否必须预取小图像块的每个地址?还是仅预取行块每行中第一个像素的地址?@DavidDoria,每当您预取一个字节的数据时,其整个缓存线都将加载到缓存中。这与图像的关系取决于在CPU架构、内存对齐等方面。一般来说,我会假设预加载每行的第一个像素就足够了。如果有疑问,请尝试这两种方法并对其进行基准测试。使用扫描线存储系统,我是否必须预取小图像块的每个地址?还是仅预取图像块每行的第一个像素的地址w block?@DavidDoria,每当预取一个字节的数据时,它的整个缓存线都会加载到缓存中。这与图像的关系取决于CPU架构、内存对齐等。一般来说,我认为预加载每行的第一个像素就足够了。如果有疑问,请尝试这两种方法并对其进行基准测试。
// Read and operate on the pixels
for(pixels in first row)
{
doSomething(pixels[i])
}