假设a1
,b1
,c1
,并d1
指向堆内存和我的数字代码具有下列核心循环.
const int n = 100000;
for (int j = 0; j < n; j++) {
a1[j] += b1[j];
c1[j] += d1[j];
}
Run Code Online (Sandbox Code Playgroud)
该循环通过另一个外for
循环执行10,000次.为了加快速度,我将代码更改为:
for (int j = 0; j < n; j++) {
a1[j] += b1[j];
}
for (int j = 0; j < n; j++) {
c1[j] += d1[j];
}
Run Code Online (Sandbox Code Playgroud)
在MS Visual C++ 10.0上进行了全面优化编译,在Intel Core 2 Duo(x64)上为32位启用了SSE2,第一个示例需要5.5秒,双循环示例仅需1.9秒.我的问题是:(请参考我在底部的改写问题)
PS:我不确定,如果这有帮助:
第一个循环的反汇编基本上是这样的(这个块在整个程序中重复大约五次):
movsd xmm0,mmword ptr [edx+18h]
addsd …
Run Code Online (Sandbox Code Playgroud) 我正在对科学应用进行一些数值优化.我注意到的一件事是GCC会pow(a,2)
通过编译来优化调用a*a
,但调用pow(a,6)
没有优化,实际上会调用库函数pow
,这会大大降低性能.(相比之下,英特尔C++编译器,可执行文件icc
,将消除库调用pow(a,6)
.)
我很好奇的是,当我更换pow(a,6)
与a*a*a*a*a*a
使用GCC 4.5.1和选项" -O3 -lm -funroll-loops -msse4
",它采用5分mulsd
的说明:
movapd %xmm14, %xmm13
mulsd %xmm14, %xmm13
mulsd %xmm14, %xmm13
mulsd %xmm14, %xmm13
mulsd %xmm14, %xmm13
mulsd %xmm14, %xmm13
Run Code Online (Sandbox Code Playgroud)
如果我写(a*a*a)*(a*a*a)
,它会产生
movapd %xmm14, %xmm13
mulsd %xmm14, %xmm13
mulsd %xmm14, %xmm13
mulsd %xmm13, %xmm13
Run Code Online (Sandbox Code Playgroud)
这将乘法指令的数量减少到3. icc
具有类似的行为.
为什么编译器不能识别这种优化技巧?
我一直在寻找最快的方法来处理popcount
大数据.我遇到了一个很奇怪的效果:改变从循环变量unsigned
至uint64_t
50%在我的电脑上所做的性能下降.
#include <iostream>
#include <chrono>
#include <x86intrin.h>
int main(int argc, char* argv[]) {
using namespace std;
if (argc != 2) {
cerr << "usage: array_size in MB" << endl;
return -1;
}
uint64_t size = atol(argv[1])<<20;
uint64_t* buffer = new uint64_t[size/8];
char* charbuffer = reinterpret_cast<char*>(buffer);
for (unsigned i=0; i<size; ++i)
charbuffer[i] = rand()%256;
uint64_t count,duration;
chrono::time_point<chrono::system_clock> startP,endP;
{
startP = chrono::system_clock::now();
count = 0;
for( unsigned k = 0; k < …
Run Code Online (Sandbox Code Playgroud) 我在Swift Beta中实现了一个算法,并注意到性能非常差.在深入挖掘之后,我意识到其中一个瓶颈就像排序数组一样简单.相关部分在这里:
let n = 1000000
var x = [Int](repeating: 0, count: n)
for i in 0..<n {
x[i] = random()
}
// start clock here
let y = sort(x)
// stop clock here
Run Code Online (Sandbox Code Playgroud)
在C++中,类似的操作在我的计算机上需要0.06秒.
在Python中,它需要0.6秒(没有技巧,只有y =排序(x)表示整数列表).
在Swift中,如果我使用以下命令编译它需要6秒:
xcrun swift -O3 -sdk `xcrun --show-sdk-path --sdk macosx`
Run Code Online (Sandbox Code Playgroud)
如果我使用以下命令编译它需要多达88秒:
xcrun swift -O0 -sdk `xcrun --show-sdk-path --sdk macosx`
Run Code Online (Sandbox Code Playgroud)
Xcode中使用"Release"与"Debug"构建的计时相似.
这有什么不对?与C++相比,我可以理解一些性能损失,但与纯Python相比,速度没有降低10倍.
编辑:天气注意到,改变-O3
以-Ofast
使这个代码的运行几乎一样快如C++版本!但是,-Ofast
更改了语言的语义 - 在我的测试中,它禁用了对整数溢出和数组索引溢出的检查.例如,使用-Ofast
以下Swift代码以静默方式运行而不会崩溃(并打印出一些垃圾):
let …
Run Code Online (Sandbox Code Playgroud) 我在2009年首先注意到GCC(至少在我的项目和我的机器上)如果我优化尺寸(-Os
)而不是速度(-O2
或-O3
),则会产生明显更快的代码,我一直想知道为什么.
我设法创建(相当愚蠢)代码,显示这种令人惊讶的行为,并且足够小,无法在此处发布.
const int LOOP_BOUND = 200000000;
__attribute__((noinline))
static int add(const int& x, const int& y) {
return x + y;
}
__attribute__((noinline))
static int work(int xval, int yval) {
int sum(0);
for (int i=0; i<LOOP_BOUND; ++i) {
int x(xval+sum);
int y(yval+sum);
int z = add(x, y);
sum += z;
}
return sum;
}
int main(int , char* argv[]) {
int result = work(*argv[1], *argv[2]);
return result;
}
Run Code Online (Sandbox Code Playgroud)
如果我用-Os
它编译它,执行这个程序需要0.38秒,如果用-O2 …
可能重复:
C++:什么时候有挥发性关键字帮你?
我从来没有用过它,但我想知道为什么人们会用它?它到底是做什么的?我搜索了论坛,发现它只是C#或Java主题.
据我所知,引用/指针别名会阻碍编译器生成优化代码的能力,因为它们必须确保在两个引用/指针确实是别名的情况下,生成的二进制文件的行为正确。例如,在以下C代码中,
void adds(int *a, int *b) {
*a += *b;
*a += *b;
}
Run Code Online (Sandbox Code Playgroud)
当clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)
用-O3
标志编译时,它发出
0000000000000000 <adds>:
0: 8b 07 mov (%rdi),%eax
2: 03 06 add (%rsi),%eax
4: 89 07 mov %eax,(%rdi) # The first time
6: 03 06 add (%rsi),%eax
8: 89 07 mov %eax,(%rdi) # The second time
a: c3 retq
Run Code Online (Sandbox Code Playgroud)
下面的代码存回(%rdi)
两次的情况下,int *a
和int *b
别名。
当我们明确告诉编译器这两个指针不能使用restrict
关键字别名时:
void adds(int * restrict a, int * restrict …
Run Code Online (Sandbox Code Playgroud) 这是从运行脚本以检查Tensorflow是否正常工作时收到的消息:
I tensorflow/stream_executor/dso_loader.cc:125] successfully opened CUDA library libcublas.so.8.0 locally
I tensorflow/stream_executor/dso_loader.cc:125] successfully opened CUDA library libcudnn.so.5 locally
I tensorflow/stream_executor/dso_loader.cc:125] successfully opened CUDA library libcufft.so.8.0 locally
I tensorflow/stream_executor/dso_loader.cc:125] successfully opened CUDA library libcuda.so.1 locally
I tensorflow/stream_executor/dso_loader.cc:125] successfully opened CUDA library libcurand.so.8.0 locally
W tensorflow/core/platform/cpu_feature_guard.cc:95] The TensorFlow library wasn't compiled to use SSE4.2 instructions, but these are available on your machine and could speed up CPU computations.
W tensorflow/core/platform/cpu_feature_guard.cc:95] The TensorFlow library wasn't compiled to use AVX instructions, but these are available …
Run Code Online (Sandbox Code Playgroud) #include <stdio.h>
volatile int i;
int main()
{
int c;
for (i = 0; i < 3; i++)
{
c = i &&& i;
printf("%d\n", c);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
上面编译的程序的输出gcc
是
0
1
1
Run Code Online (Sandbox Code Playgroud)
使用-Wall
或-Waddress
选项,gcc
发出警告:
warning: the address of ‘i’ will always evaluate as ‘true’ [-Waddress]
Run Code Online (Sandbox Code Playgroud)
如何c
在上述计划中进行评估?
在编写优化ftol
函数时,我发现了一些非常奇怪的行为GCC 4.6.1
.让我先向您展示代码(为清楚起见,我标记了差异):
fast_trunc_one,C:
int fast_trunc_one(int i) {
int mantissa, exponent, sign, r;
mantissa = (i & 0x07fffff) | 0x800000;
exponent = 150 - ((i >> 23) & 0xff);
sign = i & 0x80000000;
if (exponent < 0) {
r = mantissa << -exponent; /* diff */
} else {
r = mantissa >> exponent; /* diff */
}
return (r ^ -sign) + sign; /* diff */
}
Run Code Online (Sandbox Code Playgroud)
fast_trunc_two,C:
int fast_trunc_two(int i) {
int mantissa, exponent, …
Run Code Online (Sandbox Code Playgroud) c++ ×5
performance ×4
assembly ×3
c ×3
gcc ×3
x86 ×3
fast-math ×1
gcc-warning ×1
llvm-codegen ×1
operators ×1
rust ×1
simd ×1
sorting ×1
swift ×1
tensorflow ×1
volatile ×1
x86-64 ×1
xcode6 ×1