OpenMP 为内联函数声明 SIMD

2024-04-13

The 当前的 OpenMP 标准 http://www.openmp.org/mp-documents/openmp-4.5.pdf#subsection.2.8.2说关于declare simdC/C++ 指令:

在函数上使用声明 simd 构造可以创建 相关函数的 SIMD 版本可用于 在 SIMD 循环中处理来自单次调用的多个参数 同时。

本章中给出了更多详细信息,但对该指令可以应用的函数类型似乎没有限制。

所以我的问题是,该指令是否可以安全地应用于inline功能?

我这么问有两个原因:

  1. An inlinefunction 是一个相当不寻常的函数,因为它通常直接内联在调用它的地方。因此它可能永远不会编译为独立函数,因此,declare simd它的方面与可能的情况相当多余simd封闭循环级别的指令。
  2. 我有这样的代码inline declare simd函数,有时,出于某些模糊的原因,GCC 会抱怨它们在链接时的多重定义(名称被额外的字符破坏,表明这些是矢量化版本)。但如果我删除declare simd指令,它可以很好地编译和链接。

到目前为止我还没有想太多,但现在我很困惑。这是我的一个错误吗(即使用declare simd for inline函数)或者是 GCC 生成二进制向量化版本的问题inline函数并未能在链接时对它们进行排序?


EDIT:
有一个 GCC 编译器选项会有所不同。当启用内联时(使用-O3例如),代码可以正常编译和链接。但是当编译时-O0或与-O3 -fno-inline,内联被禁用,链接失败,并且该函数的“多重定义”装饰有omp declare simd指示。


EDIT 2:
感谢@Zboson 关于编译器标志的问题,我成功创建了一个重现器。这里是:

foobar.h:

#ifndef FOOBAR_H_
#define FOOBAR_H_

#include <cmath>

#pragma omp declare simd
inline double foo( double d ) {
    return sin( cos( exp( d ) ) );
}

double bar( double *v, int len );

#endif

foob​​ar.cc:

#include "foobar.h"

double bar( double *v, int len ) {
    double sum = 0;
    for ( int i = 0; i < len; i++ ) {
        sum += foo( v[i] );
    }
    return sum;
}

simd.cc:

#include <iostream>
#include "foobar.h"

int main() {

    const int len = 100;
    double *v = new double[len];

    for ( int i = 0; i < len; i++ ) {
        v[i] = i;
    }

    double sum = 0;
    #pragma omp simd reduction( +: sum )
    for ( int i = 0; i < len; i++ ) {
        sum += foo( v[i] );
    }

    std::cout << sum << "  " << bar( v, len ) << std::endl;

    delete[] v;

    return 0;
}

汇编:

> g++ -fopenmp -g simd.cc foobar.cc
/tmp/ccI4e7ip.o: In function `_ZGVbN2v__Z3food':
foobar.h:7: multiple definition of `_ZGVbN2v__Z3food'
/tmp/cc4U8Qyu.o:foobar.h:7: first defined here
/tmp/ccI4e7ip.o: In function `_ZGVbM2v__Z3food':
foobar.h:7: multiple definition of `_ZGVbM2v__Z3food'
/tmp/cc4U8Qyu.o:foobar.h:7: first defined here
/tmp/ccI4e7ip.o: In function `_ZGVcN4v__Z3food':
foobar.h:7: multiple definition of `_ZGVcN4v__Z3food'
/tmp/cc4U8Qyu.o:foobar.h:7: first defined here
/tmp/ccI4e7ip.o: In function `_ZGVcM4v__Z3food':
foobar.h:7: multiple definition of `_ZGVcM4v__Z3food'
foobar.h:7: first defined here
/tmp/ccI4e7ip.o: In function `_ZGVdN4v__Z3food':
foobar.h:7: multiple definition of `_ZGVdN4v__Z3food'
foobar.h:7: first defined here
/tmp/ccI4e7ip.o: In function `_ZGVdM4v__Z3food':
foobar.h:7: multiple definition of `_ZGVdM4v__Z3food'
foobar.h:7: first defined here
collect2: error: ld returned 1 exit status
> c++filt _ZGVdM4v__Z3food
_ZGVdM4v__Z3food
> c++filt _Z3food
foo(double)

Gcc 版本 4.9.2 和 5.1.0 都给出了完全相同的问题,而 Intel 编译器版本 15.0.3 编译得很好。


最终编辑:
赫里斯托·伊利耶夫的评论 https://stackoverflow.com/questions/34091341/openmp-declare-simd-for-an-inline-function#comment55959437_34097496 and Z玻色子的问题 https://stackoverflow.com/q/34110703/5239503让我感到安慰的是,我的代码符合 OpenMP 标准,而且这是 GCC 中的一个错误。我将尝试使用我能找到的最新版本进行进一步测试,并在需要时进行报告。


内联函数是一个相当不寻常的函数,因为它通常直接内联在调用它的地方。因此它可能永远不会被编译为独立函数。

这是不正确的。除非声明,否则具有或不具有内联的函数static具有外部链接。编译器必须生成该函数的独立版本(不会内联),以防从另一个目标文件调用该函数。如果您不需要独立函数,请声明该函数static。请参阅 Agner Fog 的第 8.3 节和标题“内联函数有一个非内联副本”用 C++ 优化软件 http://www.agner.org/optimize/optimizing_cpp.pdf更多细节。

Using static inline double foo您的代码不会出现错误。

现在让我们看看这些符号。不使用static

nm foobar.o | grep foo

gives

W _Z3food
T _ZGVbM2v__Z3food
T _ZGVbN2v__Z3food
T _ZGVcM4v__Z3food
T _ZGVcN4v__Z3food
T _ZGVdM4v__Z3food
T _ZGVdN4v__Z3food

and nm foobar.o | grep foo给出同样的东西。

大写“W”和“T”表示符号是外部的。然而“W”是弱符号 https://en.wikipedia.org/wiki/Weak_symbol这不会导致链接错误,但是“T”是一个强符号,会导致链接错误。这说明了链接器抱怨的原因。

结果是什么static inline?在这种情况下nm foobar.o | grep foo gives

t _ZGVbM2v__ZL3food
t _ZGVbN2v__ZL3food
t _ZL3food

and nm simd.o | grep foo给出同样的东西。但小写“t”表示符号具有本地链接,因此链接器没有问题。

如果我们不使用 OpenMP 进行编译foo产生的符号是_ZL3food。我不知道为什么 GCC 为函数的非 SIMD 版本生成弱符号,为 SIMD 版本生成强符号,所以我无法完全回答你的问题,但我认为这个信息仍然很有趣。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

OpenMP 为内联函数声明 SIMD 的相关文章

  • Tensorflow 中的自定义资源

    由于某些原因 我需要为 Tensorflow 实现自定义资源 我试图从查找表实现中获得灵感 如果我理解得好的话 我需要实现3个TF操作 创建我的资源 资源的初始化 例如 在查找表的情况下填充哈希表 执行查找 查找 查询步骤 为了促进实施 我
  • C++ 中的软(不是:弱)引用 - 这可能吗?有实施吗?

    在 C 中我正在使用boost shared ptr and boost weak ptr自动删除不再需要的对象 我知道这些与引用计数一起工作 在 Java 中 内存由垃圾收集器管理 它将内置对象引用视为strong WeakReferen
  • 将处理后的图形绘制到另一个图形中

    我想将一个经过处理的图形绘制到另一个图形中 I have two graphics var gHead Graphics FromImage h var gBackground Graphics FromImage b Transform
  • MEX 文件中的断言导致 Matlab 崩溃

    我正在使用mxAssert 宏定义为matrix h在我的 C 代码中 mex 可以完美编译 当我调用的 mex 代码中违反断言时 该断言不会导致我的程序崩溃 而是导致 Matlab 本身崩溃 我错过了什么吗 这是有意的行为吗 当我查看 M
  • 在 OpenCL 中将函数作为参数传递

    是否可以在 OpenCL 1 2 中将函数指针传递给内核 我知道可以用C实现 但不知道如何在OpenCL的C中实现 编辑 我想做这篇文章中描述的同样的事情 在 C 中如何将函数作为参数传递 https stackoverflow com q
  • 有什么工具可以说明每种方法运行需要多长时间?

    我的程序的某些部分速度很慢 我想知道是否有我可以使用的工具 例如它可以告诉我可以运行 methodA 花了 100ms 等等 或者类似的有用信息 如果您使用的是 Visual Studio Team System 性能工具 中有一个内置分析
  • Linux TUN/TAP:无法从 TAP 设备读回数据

    问题是关于如何正确配置想要使用 Tun Tap 模块的 Linux 主机 My Goal 利用现有的路由软件 以下为APP1和APP2 但拦截并修改其发送和接收的所有消息 由Mediator完成 我的场景 Ubuntu 10 04 Mach
  • std::map 和二叉搜索树

    我读过 std map 是使用二叉搜索树数据结构实现的 BST 是一种顺序数据结构 类似于数组中的元素 它将元素存储在 BST 节点中并按其顺序维护元素 例如如果元素小于节点 则将其存储在节点的左侧 如果元素大于节点 则将其存储在节点的右侧
  • 调试内存不足异常

    在修复我制作的小型 ASP NET C Web 应用程序的错误时 我遇到了 OutOfMemoryException 没有关于在哪里查看的提示 因为这是一个编译时错误 如何诊断此异常 我假设这正是内存分析发挥作用的地方 有小费吗 Thank
  • 获取从属性构造函数内部应用到哪个属性的成员?

    我有一个自定义属性 在自定义属性的构造函数内 我想将属性的属性值设置为属性所应用到的属性的类型 是否有某种方式可以访问该属性所应用到的成员从我的属性类内部 可以从 NET 4 5 using CallerMemberName Somethi
  • 为什么 BOOST_FOREACH 不完全等同于手工编码的?

    From 增强文档 http www boost org doc libs 1 48 0 doc html foreach html foreach introduction what is literal boost foreach li
  • 在 C# 中将位从 ulong 复制到 long

    所以看来 NET 性能计数器类型 http msdn microsoft com en us library system diagnostics performancecounter aspx有一个恼人的问题 它暴露了long对于计数器
  • 单元测试失败,异常代码为 c0000005

    我正在尝试使用本机单元测试项目在 Visual Studios 2012 中创建单元测试 这是我的测试 TEST METHOD CalculationsRoundTests int result Calculations Round 1 0
  • 事件日志写入错误

    很简单 我想向事件日志写入一些内容 protected override void OnStop TODO Add code here to perform any tear down necessary to stop your serv
  • “MyClass”的类型初始值设定项引发异常

    以下是我的Windows服务代码 当我调试代码时 我收到错误 异常 CSMessageUtility CSDetails 的类型初始值设定项引发异常 using System using System Collections Generic
  • std::bind 重载解析

    下面的代码工作正常 include
  • 32位PPC rlwinm指令

    我在理解上有点困难rlwinmPPC 汇编指令 旋转左字立即然后与掩码 我正在尝试反转函数的这一部分 rlwinm r3 r3 0 28 28 我已经知道什么了r3 is r3在本例中是一个 4 字节整数 但我不确定这条指令到底是什么rlw
  • gdb查找行号的内存地址

    假设我已将 gdb 附加到一个进程 并且在其内存布局中有一个文件和行号 我想要其内存地址 如何获取文件x中第n行的内存地址 这是在 Linux x86 上 gdb info line test c 56 Line 56 of test c
  • boost::program_options:带有固定和可变标记的参数?

    是否可以在 boost program options 中使用此类参数 program p1 123 p2 234 p3 345 p12 678 即 是否可以使用第一个标记指定参数名称 例如 p 后跟一个数字 是动态的吗 我想避免这种情况
  • 如何确定母版页中正在显示哪个子页?

    我正在母版页上编写代码 我需要知道正在显示哪个子 内容 页面 我怎样才能以编程方式做到这一点 我用这个 string pageName this ContentPlaceHolder1 Page GetType FullName 它以 AS

随机推荐