我知道各种数据类型的大小可能会根据我所使用的系统而改变.我使用XP 32位,并在C++中使用sizeof()运算符,似乎long double是12个字节,double是8.
但是,大多数主要消息来源都表示long double是8个字节,因此范围与double相同.
为什么我有12个字节?如果long double确实是12个字节,那么这也不会扩展值的范围吗?或者,当值超出double的范围时,仅使用长签名(编译器数字),因此,超出8个字节?
谢谢.
有些人不知道可以通过C中的值传递和返回结构.我的问题是关于编译器在C中返回结构时制作不必要的副本.诸如GCC之类的C编译器是使用返回值优化(RVO)优化还是仅仅是C++概念?我读过的关于RVO和copy elision的所有内容都与C++有关.
让我们考虑一个例子.我目前正在用C 实现一个双重数据类型(或者更确切地说是float-float,因为我觉得它很容易进行单元测试).请考虑以下代码.
typedef struct {
float hi;
float lo;
} doublefloat;
doublefloat quick_two_sum(float a, float b) {
float s = a + b;
float e = b - (s - a);
return (doublefloat){s, e};
}
Run Code Online (Sandbox Code Playgroud)
编译器是否会复制doublefloat我返回的值,还是可以省略临时副本?
在C中命名的返回值优化(NRVO)怎么样?我有另一个功能
doublefloat df64_add(doublefloat a, doublefloat b) {
doublefloat s, t;
s = two_sum(a.hi, b.hi);
t = two_sum(a.lo, b.lo);
s.lo += t.hi;
s = quick_two_sum(s.hi, s.lo);
s.lo += t.lo;
s = quick_two_sum(s.hi, s.lo);
return s; …Run Code Online (Sandbox Code Playgroud) 我想使用增强的REP MOVSB(ERMSB)为自定义获得高带宽memcpy.
ERMSB引入了Ivy Bridge微体系结构.如果您不知道ERMSB是什么,请参阅英特尔优化手册中的"增强型REP MOVSB和STOSB操作(ERMSB)" 部分.
我知道直接执行此操作的唯一方法是使用内联汇编.我从https://groups.google.com/forum/#!topic/gnu.gcc.help/-Bmlm_EG_fE获得了以下功能
static inline void *__movsb(void *d, const void *s, size_t n) {
asm volatile ("rep movsb"
: "=D" (d),
"=S" (s),
"=c" (n)
: "0" (d),
"1" (s),
"2" (n)
: "memory");
return d;
}
Run Code Online (Sandbox Code Playgroud)
然而,当我使用它时,带宽远小于memcpy.
使用我的i7-6700HQ(Skylake)系统,Ubuntu 16.10,DDR4 @ 2400 MHz双通道32 GB,GCC 6.2,__movsb获得15 GB/s并memcpy获得26 GB/s.
为什么带宽如此低REP MOVSB?我该怎么做才能改善它?
这是我用来测试它的代码.
//gcc -O3 -march=native -fopenmp foo.c
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include …Run Code Online (Sandbox Code Playgroud) #pragma omp parallel
{
int x; // private to each thread ?
}
#pragma omp parallel for
for (int i = 0; i < 1000; ++i)
{
int x; // private to each thread ?
}
Run Code Online (Sandbox Code Playgroud)
谢谢!
PS如果局部变量是自动私有的,那么使用私有子句有什么意义呢?
我试图在L1缓存中获得全部带宽,以便在Intel处理器上实现以下功能
float triad(float *x, float *y, float *z, const int n) {
float k = 3.14159f;
for(int i=0; i<n; i++) {
z[i] = x[i] + k*y[i];
}
}
Run Code Online (Sandbox Code Playgroud)
这是STREAM的三合一功能.
使用具有此功能的SandyBridge/IvyBridge处理器可获得约95%的峰值(使用NASM组装).但是,除非我展开循环,否则使用Haswell I仅达到峰值的62%.如果我展开16次,我得到92%.我不明白这一点.
我决定使用NASM在汇编中编写我的函数.装配中的主循环看起来像这样.
.L2:
vmovaps ymm1, [rdi+rax]
vfmadd231ps ymm1, ymm2, [rsi+rax]
vmovaps [rdx+rax], ymm1
add rax, 32
jne .L2
Run Code Online (Sandbox Code Playgroud)
在示例12.7-12.11 中的Agner Fog的优化组装手册中,他y[i] = y[i] +k*x[i]对Pentium M,Core 2,Sandy Bridge,FMA4和FMA3 做了几乎相同的事情(但是).我设法或多或少地自己重现了他的代码(实际上他在广播时在FMA3示例中有一个小错误).除FMA4和FMA3外,他为每个处理器的表格提供指令大小计数,融合操作,执行端口.我曾试图为FMA3制作这张桌子.
ports
size ?ops-fused 0 1 2 3 4 5 6 7
vmovaps 5 1 ½ ½ …Run Code Online (Sandbox Code Playgroud) 我使用英特尔®架构代码分析器(IACA)发现了一些意想不到的东西(对我而言).
以下指令使用[base+index]寻址
addps xmm1, xmmword ptr [rsi+rax*1]
Run Code Online (Sandbox Code Playgroud)
根据IACA没有微熔丝.但是,如果我用[base+offset]这样的
addps xmm1, xmmword ptr [rsi]
Run Code Online (Sandbox Code Playgroud)
IACA报告它确实融合了.
英特尔优化参考手册的第2-11节给出了以下"可以由所有解码器处理的微融合微操作"的示例
FADD DOUBLE PTR [RDI + RSI*8]
Run Code Online (Sandbox Code Playgroud)
和Agner Fog的优化装配手册也给出了使用[base+index]寻址的微操作融合的例子.例如,请参见第12.2节"Core2上的相同示例".那么正确的答案是什么?
我们N是一个编译时无符号整数.
GCC可以优化
unsigned sum = 0;
for(unsigned i=0; i<N; i++) sum += a; // a is an unsigned integer
Run Code Online (Sandbox Code Playgroud)
简单地说 a*N.这可以理解,因为模数运算说(a%k + b%k)%k = (a+b)%k.
但GCC不会优化
float sum = 0;
for(unsigned i=0; i<N; i++) sum += a; // a is a float
Run Code Online (Sandbox Code Playgroud)
到a*(float)N.
但是通过使用关联数学,-Ofast我发现GCC可以按顺序减少这一点log2(N).例如,因为N=8它可以在三个添加中进行总和.
sum = a + a
sum = sum + sum // (a + a) + (a + a)
sum = sum + sum …Run Code Online (Sandbox Code Playgroud) 我发现在MSVC(在Windows上)和GCC(在Linux上)为Ivy Bridge系统编译的代码之间的性能差异很大.代码执行密集矩阵乘法.我使用GCC获得了70%的峰值失误,而MSVC只获得了50%.我想我可能已经把他们两个内在函数如何转换的差异分开了.
__m256 breg0 = _mm256_loadu_ps(&b[8*i])
_mm256_add_ps(_mm256_mul_ps(arge0,breg0), tmp0)
Run Code Online (Sandbox Code Playgroud)
GCC这样做
vmovups ymm9, YMMWORD PTR [rax-256]
vmulps ymm9, ymm0, ymm9
vaddps ymm8, ymm8, ymm9
Run Code Online (Sandbox Code Playgroud)
MSVC这样做
vmulps ymm1, ymm2, YMMWORD PTR [rax-256]
vaddps ymm3, ymm1, ymm3
Run Code Online (Sandbox Code Playgroud)
有人可以向我解释这两种解决方案是否以及为何能够在性能上产生如此大的差异?
尽管MSVC使用少一条指令,但它会将负载与多线程联系起来,这可能会使它更加依赖(也许负载无法按顺序完成)?我的意思是Ivy Bridge可以在一个时钟周期内完成一个AVX加载,一个AVX mult和一个AVX加载,但这要求每个操作都是独立的.
也许问题出在其他地方?您可以在下面看到最里面循环的GCC和MSVC的完整汇编代码.你可以在这里看到循环的C++代码循环展开以实现Ivy Bridge和Haswell的最大吞吐量
g ++ -S -masm = intel matrix.cpp -O3 -mavx -fopenmp
.L4:
vbroadcastss ymm0, DWORD PTR [rcx+rdx*4]
add rdx, 1
add rax, 256
vmovups ymm9, YMMWORD PTR [rax-256]
vmulps ymm9, ymm0, ymm9
vaddps ymm8, ymm8, ymm9
vmovups ymm9, YMMWORD PTR [rax-224] …Run Code Online (Sandbox Code Playgroud) C99添加了一个宏__STDC_IEC_559__,可用于测试编译器和标准库是否符合ISO/IEC/IEEE 60559(或IEEE 754)标准.
根据这个问题的答案,
如何检查-ieee-754-单精度-32位浮点表示,大多数C编译器不设置预处理器宏__STDC_IEC_559__.
根据海湾合作委员会的文件,它没有定义__STDC_IEC_559__.
我用GCC 4.9.2和Clang 3.6.0测试了这两个,使用glibc2.21使用以下代码.
//test.c
//#include <features.h>
int main(void) {
#if defined ( __STDC_IEC_559__ )
//#if defined ( __GCC_IEC_559__ )
return 1;
#else
return 0;
#endif
}
Run Code Online (Sandbox Code Playgroud)
然后
echo $?
Run Code Online (Sandbox Code Playgroud)
这表明此代码__STDC_IEC_559__是使用GCC定义的,而不是使用Clang定义的.然后我做了gcc -E,它显示该文件stdc-predef.h包含在内.这个文件定义__STDC_IEC_559__.
/* glibc's intent is to support the IEC 559 math functionality, real
and complex. If the GCC (4.9 and later) predefined macros
specifying compiler intent …Run Code Online (Sandbox Code Playgroud) 我有一个i5-4250U,它有AVX2和FMA3.我正在测试Linux上的GCC 4.8.1中的一些密集矩阵乘法代码.下面是我编译的三种不同方式的列表.
SSE2: gcc matrix.cpp -o matrix_gcc -O3 -msse2 -fopenmp
AVX: gcc matrix.cpp -o matrix_gcc -O3 -mavx -fopenmp
AVX2+FMA: gcc matrix.cpp -o matrix_gcc -O3 -march=native -fopenmp -ffast-math
Run Code Online (Sandbox Code Playgroud)
SSE2和AVX版本的性能明显不同.但是,AVX2 + FMA并不比AVX版本好.我不明白这一点.假设没有FMA,我获得了超过80%的CPU峰值触发器,但我认为我应该能够用FMA做得更好.矩阵乘法应直接受益于FMA.我基本上是在AVX中同时做八个点产品.当我检查march=native它给出:
cc -march=native -E -v - </dev/null 2>&1 | grep cc1 | grep fma
...-march=core-avx2 -mavx -mavx2 -mfma -mno-fma4 -msse4.2 -msse4.1 ...
Run Code Online (Sandbox Code Playgroud)
所以我可以看到它已启用(只是为了确保我添加-mfma但它没有区别). ffast-math应该允许宽松的浮点模型如何在SSE/AVX中使用融合乘法 - 加法(FMA)指令
编辑:
基于Mysticial的评论我继续使用_mm256_fmadd_ps,现在AVX2 + FMA版本更快. 我不确定为什么编译器不会为我这样做. 对于超过1000x1000的矩阵,我现在得到大约80 GFLOPS(没有FMA的110%的峰值触发器).如果有人不信任我的峰值翻牌计算,这就是我所做的.
peak flops (no FMA) = frequency * simd_width * ILP * cores …Run Code Online (Sandbox Code Playgroud)