繁体   English   中英

现代c ++编译器是否为24位图像处理自动生成代码?

[英]Do modern c++ compilers autovectorize code for 24bit image processing?

像gcc,visual studio c ++,intel c ++编译器,clang等编译器会像以下那样对代码进行矢量化吗?

std::vector<unsigned char> img( height * width * 3 );
unsigned char channelMultiplier[3];

// ... initialize img and channelMultiplier ...

for ( int y = 0; y < height; ++y )
    for ( int x = 0; x < width; ++x )
        for ( b = 0; b < 3; ++b )
            img[ b+3*(x+width*y) ] = img[ b+3*(x+width*y) ] * 
                                     channelMultiplier[b] / 0x100;

32位图像处理的情况怎么样?

我不认为你的tripple循环会自动矢量化。 IMO的问题是:

  • 通过对象类型std :: vector访问内存。 AFAIK我认为除非访问运算符[]或()被内联,否则任何编译器都不会自动向量化std :: vector代码,但我不清楚它是否会自动向量化。
  • 您的代码受到内存别名的影响,即编译器不知道您引用img的内存是否是从另一个内存指针访问的,这很可能会阻止向量化。 基本上你需要定义一个普通的双数组,并提示编译器没有其他指针指向同一个位置。 我认为你可以使用__restrict来做到这一点。 __restrict告诉编译器该指针是指向该内存位置的唯一指针,并且没有其他指针,因此不存在副作用的风险。
  • 默认情况下,内存未对齐,即使编译器设法自动向量化,未对齐内存的向量化也比对齐内存慢很多。 您需要确保您的存储器是32个存储器位地址对齐以利用自动向量化和AVX到最大和16位地址对齐以最大限度地利用SSE,即始终对齐到32个存储器位地址。 这可以通过以下方式动态完成:

     double* buffer = NULL; posix_memalign((void**) &buffer, 32, size*sizeof(double)); ... free(buffer); 

在MSVC中,您可以使用__declspec(align(32)) double array[size]执行此操作,但您必须使用您正在使用的特定编译器进行检查,以确保使用正确的对齐指令。

另一个重要的事情,如果你使用GNU编译器使用标志-ftree-vectorizer-verbose=6来检查你的循环是否正在自动矢量化。 如果使用英特尔编译器,则使用-vec-report5 请注意,有多个级别的详细程度和信息输出,即6和5数字,因此请查看编译器文档。 详细级别越高,您将为代码中的每个循环获得的矢量化信息越多,但编译器在发布模式下编译的速度越慢。

一般来说,我总是感到惊讶的是如何让编译器自动向量化并不容易,这是一个常见的错误,因为循环看起来是规范的,然后编译器会自动地自动向量化它。

更新:还有一件事,确保你的img实际上是页面对齐的posix_memalign((void**) &buffer, sysconf(_SC_PAGESIZE), size*sizeof(double)); (这意味着AVX和SSE对齐)。 问题是,如果你有一个大图像,这个循环很可能在执行期间最终页面切换,这也是非常昂贵的。 我认为这就是所谓的TLB未命中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM