这个网站上已经存在很多性能问题,但是我发现几乎所有这些都是特定于问题且相当狭窄的问题.几乎所有人都重复这些建议,以避免过早优化.
我们假设:
我在这里寻找的是在一个关键算法中挤出最后几个百分点的策略和技巧,除此之外别无他法.
理想情况下,尝试使答案语言不可知,并在适用的情况下指出建议策略的任何缺点.
我将使用我自己的初步建议添加回复,并期待Stack Overflow社区可以想到的任何其他内容.
我经常注意到gcc将乘法转换为可执行文件中的移位.当乘以a int和a 时,可能会发生类似的事情float.例如,2 * f可能只是将指数递增f1,从而节省了一些周期.编译器,也许是一个人请求他们这样做(例如通过-ffast-math),一般来说,这样做吗?
编译器通常是否足够聪明,或者我是否需要使用scalb*()或ldexp()/frexp()函数系列自己完成此操作?
当我第一次使用Haswell处理器时,我尝试使用FMA来确定Mandelbrot集.主要算法是这样的:
intn = 0;
for(int32_t i=0; i<maxiter; i++) {
floatn x2 = square(x), y2 = square(y); //square(x) = x*x
floatn r2 = x2 + y2;
booln mask = r2<cut; //booln is in the float domain non integer domain
if(!horizontal_or(mask)) break; //_mm256_testz_pd(mask)
n -= mask
floatn t = x*y; mul2(t); //mul2(t): t*=2
x = x2 - y2 + cx;
y = t + cy;
}
Run Code Online (Sandbox Code Playgroud)
这确定n像素是否在Mandelbrot集中.因此对于双浮点,它运行超过4个像素(floatn = __m256d,intn = __m256i).这需要4个SIMD浮点乘法和4个SIMD浮点加法.
然后我修改了这个就像这样使用FMA
intn n = 0; …Run Code Online (Sandbox Code Playgroud) 即使在阅读了相当多的严格别名规则后,我仍然感到困惑.据我所知,不可能实现遵循这些规则的合理的内存分配器,因为malloc永远不能重用释放的内存,因为内存可以用于在每次分配时存储不同的类型.
显然这不可能是正确的.我错过了什么?如何实现遵循严格别名的分配器(或内存池)?
谢谢.
编辑:让我用一个愚蠢的简单例子来澄清我的问题:
// s == 0 frees the pool
void *my_custom_allocator(size_t s) {
static void *pool = malloc(1000);
static int in_use = FALSE;
if( in_use || s > 1000 ) return NULL;
if( s == 0 ) {
in_use = FALSE;
return NULL;
}
in_use = TRUE;
return pool;
}
main() {
int *i = my_custom_allocator(sizeof(int));
//use int
my_custom_allocator(0);
float *f = my_custom_allocator(sizeof(float)); //not allowed...
}
Run Code Online (Sandbox Code Playgroud) 考虑到这个功能,
float mulHalf(float x) {
return x * 0.5f;
}
Run Code Online (Sandbox Code Playgroud)
以下函数与正常输入/输出产生相同的结果。
float mulHalf_opt(float x) {
__m128i e = _mm_set1_epi32(-1 << 23);
__asm__ ("paddd\t%0, %1" : "+x"(x) : "xm"(e));
return x;
}
Run Code Online (Sandbox Code Playgroud)
这是带有 的汇编输出-O3 -ffast-math。
mulHalf:
mulss xmm0, DWORD PTR .LC0[rip]
ret
mulHalf_opt:
paddd xmm0, XMMWORD PTR .LC1[rip]
ret
Run Code Online (Sandbox Code Playgroud)
-ffast-math启用-ffinite-math-only“假设参数和结果不是 NaN 或 +-Infs” [1]。
因此,如果在 的容差下生成更快的代码,则的编译输出可能会更好地与onmulHalf一起使用。paddd-ffast-math-ffast-math
我从Intel Intrinsics Guide中获得了下表。
(MULSS)
Architecture Latency Throughput (CPI)
Skylake 4 0.5 …Run Code Online (Sandbox Code Playgroud)