- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
通常,我可能会编写一个类似simd的循环:
float * x = (float *) malloc(10 * sizeof(float));
float * y = (float *) malloc(10 * sizeof(float));
for(int i = 0; i < 10; i++)
y[i] = 10;
#pragma omp simd
for(int i = 0; i < 10; i++)
x[i] = y[i]*y[i];
float square(float x) {
return x * x;
}
float halve(float x) {
return x / 2.;
}
void apply_simd(float * x, float * y, int length, float (*simd_func)(float c)){
#pragma omp simd
for(int i = 0; i < length; i++)
x[i] = simd_func(y[i])
}
float inline square(float x){ ... }
最佳答案
是的,启用优化(-O3 -march=native
),如果满足以下条件,现代编译器可以可靠地内联函数指针:
-fPIC
编译)中使用此代码,则使用
,然后使用符号插入规则意味着
float halve(float x) { return x * 0.5f; }
1即使在同一翻译单元内也不能内联。参见
Sorry state of dynamic libraries on Linux。
inline
关键字进行内联;像
static
一样,如果编译器决定在每个调用站点内联,则它根本不发出该函数的独立定义。
inline
,
halve
和
square
上使用
apply_simd
。 (因为
apply_simd
需要内联到将
halve
作为函数arg传递的调用程序中。一个单独的
apply_simd
定义是无用的,因为它不能内联未知函数。)如果它们在
.cpp
中而不是在
.h
中,则您最好也将它们设置为
static
,或者相反,否则将它们设置为
inline
。
apply_simd(x, y, length, halve); // copy y to x
apply_simd(x, x, length, square); // then update x in-place
// NEVER DO THIS, make one function that does both things
// with gcc and clang, compiles as written to two separate loops.
仅通过
0.5f
复制并乘以的循环通常会成为内存带宽的瓶颈。像Haswell(或Skylake)这样的现代CPU的FMA / mul(或增加)吞吐量(每个时钟2x 256位 vector )是其存储带宽的两倍(每个时钟1x 256位 vector 至L1d)。
计算强度很重要。不要通过编写执行单独的琐碎操作的多个循环来简化代码
x[i] = 0.25f * y[i]*y[i]
的吞吐量将与其中任何一个操作相同。
__restrict
告诉它x和y不重叠,编译器仍会进行2个单独的循环。
halve(float)
函数是不重要内容的占位符,则可以在lambda中使用它来与其他内容组合。例如
square(halve(a))
在早期的C++标准中,您需要将lambda分配给函数指针。 (
Lambda as function parameter)
// your original function mostly unchanged, but with size_t and inline
inline // allows inlining even with -fPIC
void apply_simd(float * x, const float *y, size_t length, float (*simd_func)(float c)){
#pragma omp simd
for(size_t i = 0; i < length; i++)
x[i] = simd_func(y[i]);
}
C++ 11调用者:
// __restrict isn't needed with OpenMP, but you might want to assert non-overlapping for better auto-vectorization with non-OpenMP compilers.
void test_lambda(float *__restrict x, const float *__restrict y, size_t length)
{
float (*funcptr)(float) = [](float a) -> float {
float h=0.5f*a; // halve first allows vmulps with a memory source operand
return h*h; // 0.25 * a * a doesn't optimize to that with clang :/
};
apply_simd(x, y, length, funcptr);
}
在C++ 17中,它甚至更容易,并且可以使用文字匿名lambda来工作:
void test_lambda17(float *__restrict x, const float *__restrict y, size_t length)
{
apply_simd(x, y, length, [](float a) {
float h = 0.5f*a;
return h * h;
}
);
}
它们都可以通过gcc和clang高效地编译为一个内部循环,例如
(Godbolt compiler explorer)。
.L4:
vmulps ymm0, ymm1, YMMWORD PTR [rsi+rax]
vmulps ymm0, ymm0, ymm0
vmovups YMMWORD PTR [rdi+rax], ymm0
add rax, 32
cmp rax, rcx
jne .L4
clang展开了一些,并且可能接近每个时钟加载+存储的一个256位 vector ,乘以2。 (非索引寻址模式可以通过展开隐藏两个指针增量来实现。傻傻的编译器。:/)
inline
关键字或破坏编译器内联功能的情况。这仅意味着函数地址必须是动态链接时间常数(即直到动态库的运行时绑定(bind)才知道),因此它不会使您免于插入符号的麻烦。在使用
-fPIC
进行编译时,编译器仍然不知道它可以看到的全局函数的版本是否是链接时实际解析的版本,或者
LD_PRELOAD
或主可执行文件中的符号是否会覆盖它。因此,它仅发出从GOT加载函数指针的代码,并在循环中调用它。 SIMD当然是不可能的。
constexpr
将它们作为args传递出去,然后再在模板中使用。
因此,如果不是因为gcc错误导致您无法将其与lambda结合使用,则可能要使用它。
static
)链接的形式作为模板参数传递的函数。)
template <float simd_func(float c)>
void apply_template(float *x, const float *y, size_t length){
#pragma omp simd
for(size_t i = 0; i < length; i++)
x[i] = simd_func(y[i]);
}
void test_lambda(float *__restrict x, const float *__restrict y, size_t length)
{
// static // even static doesn't help work around the gcc bug
constexpr auto my_op = [](float a) -> float {
float h=0.5f*a; // halve first allows vmulps with a memory source operand
return h*h; // 0.25 * a * a doesn't optimize to that with clang :/
};
// I don't know what the unary + operator is doing here, but some examples use it
apply_lambda<+my_op>(x, y, length); // clang accepts this, gcc doesn't
}
clang可以很好地进行编译,但是g++即使使用-std=gnu++17
也会错误地拒绝它
// `inline` is still necessary for it to actually inline with -fPIC (in a shared lib)
inline float my_func(float a) { return 0.25f * a*a;}
void test_template(float *__restrict x, const float *__restrict y, size_t length)
{
apply_lambda<my_func>(x, y, length); // not actually a lambda, just a function
}
然后,我们从g++ 8.2
-O3 -fopenmp -march=haswell
得到了这样一个内部循环。请注意,我使用
0.25f * a * a;
而不是先进行
halve
来查看我们得到了哪种错误代码。这就是g++ 8.2所做的。
.L25:
vmulps ymm0, ymm1, YMMWORD PTR [rsi+rax] # ymm0 = 0.25f * y[i+0..7]
vmulps ymm0, ymm0, YMMWORD PTR [rsi+rax] # reload the same vector again
vmovups YMMWORD PTR [rdi+rax], ymm0 # store to x[i+0..7]
add rax, 32
cmp rax, rcx
jne .L25
如果gcc未使用索引寻址模式(Haswell / Skylake上的
stops it from micro-fusing),则两次重载相同的 vector 以保存指令将是一个好主意。因此,此循环实际上发出的是7微分,每次迭代的运行最佳为7/4个周期。
x / 2.
优化为x * 0.5f
,而不必升级为
double
。
-ffast-math
的情况下,可以使用乘法而不是除法,因为
0.5f
可以精确地表示为
float
,这与分母不是2的幂的分数不同。
0.5 * x
不会优化为
0.5f * x
; gcc和clang实际上确实扩展为
double
并返回。我不确定这是否是错过的优化而不是
x / 2.
,或者不确定是否存在真正的语义差异,以至于当它可以精确地表示为
float
时,无法将double常量优化为float。
关于c++ - Open MP:SIMD循环中的SIMD兼容功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51729258/
OpenAL.org && 创意开发网站已关闭。我选择替代版本 OpenAL Soft .我很担心,因为在 OpenAL Soft 的二进制安装中我找不到 alut.h header 。 alut.h
我使用 Android Studio 已经有一段时间了,但有一天应用程序突然出错了。当我尝试单击我的目录以查找要导入或打开的文件时,应用程序变得异常缓慢并且根本没有响应。当我最终成功切换到存储我的文件
自 Firefox 4 以来,这似乎是一个奇怪的功能变化。在使用 window.open() 打开一个窗口后,当用鼠标中键单击打开的窗口中的链接时(或右键单击并选择“在新窗口中打开”选项卡') 导致链
我无法从 Open::URI 的 rdoc 中得知当我这样做时返回的是什么: result = open(url) URL 返回 XML,但我如何查看/解析 XML? 最佳答案 open 返回一个 I
经常开发asp但对于细致的说法,真实不太清楚,这里简单的介绍下。 一般情况下 读取数据都是用rs.open sql,conn,1,1 修改数据:rs.open sql,conn,1,3 删除
关于 pathlib 标准库中的模块,是 path.open() 方法只是内置 open() 的“包装器”功能? 最佳答案 如果您阅读了 source code的 pathlib.Path.open你
我想将 Open Liberty 运行时的语言更改为 en_US从 Eclipse IDE 中,但我不知道如何。 也尝试使用 JVM 参数的首选项来设置它,但它没有用。 -Duser.language
这是我所拥有的: 参数“opener”未在可能的函数调用参数中列出。这是 PyCharm 错误还是其他原因? PyCharm 2018.3.5 社区版,Windows 7 上的 Python 3.6.
我正在使用 Tinkerpop 的 GraphFactory.open(Configuration 配置) Java 命令来访问 Neo4j 数据库。 一个最低限度的工作示例是: Configurat
这个问题在这里已经有了答案: What is the python "with" statement designed for? (11 个答案) 关闭 7 年前。 我没有使用过 with 语句,但
我正在玩 python 3.5 中的 open 函数。我不明白 opener 参数(最后一个参数)在 open 函数中的用法。根据 python 文档:可以通过将可调用对象作为打开器传递来使用自定义打
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 5 年前。 Improve th
我试图用 Python 来做一些模拟 3D 声音的工作。我试图运行此代码(答案中提供):Python openAL 3D sound类似,两次都收到: ModuleNotFoundError: No
我一直认为 open 和 io.open 可以互换。 显然不是,如果我相信这个片段: import ctypes, io class POINT(ctypes.Structure): _fie
这个问题在这里已经有了答案: What's the difference between io.open() and os.open() on Python? (7 个答案) 关闭 9 年前。 我是
我正在尝试更好地了解 WCF 的一些内部工作原理。我已经做了相当多的环顾四周,但我无法找到关于 ChannelFactory.Open() 与 IClientChannel.Open() 相比的明确解
这个问题在这里已经有了答案: What is the python "with" statement designed for? (11 个答案) 关闭 7 年前。 我知道有很多关于在 python
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界. 这篇CFSDN的博客文章adodb.recordset.open(rs.open)方法参数详解由
不久前我遇到了一个interesting security hole Link 看起来足够无害,但有一个漏洞,因为默认情况下,正在打开的页面允许打开的页面通过 window.opener 回调到它。有
这在我的应用程序上运行良好,但由于某种原因我无法让它在这里正常工作。无论如何,我的问题是,当我单击列表标题时,我想关闭之前打开的列表标题并仅保留事件的列表标题打开。目前它会打开我点击的所有内容,但也会
我是一名优秀的程序员,十分优秀!