我已经告诉别人,编写using namespace std;代码是错误的,我应该用std::cout和std::cin直接代替.
为什么被using namespace std;认为是不好的做法?是低效还是冒着声明模糊变量(与名称std空间中的函数具有相同名称的变量)的风险?它会影响性能吗?
这是一个非常有趣的问题,所以让我设置场景.我在国家计算机博物馆工作,我们刚刚设法从1992年开始运行一台Cray Y-MP EL超级计算机,我们真的想看看它有多快!
我们认为最好的方法是编写一个简单的C程序来计算素数,并显示这需要多长时间,然后在快速的现代台式PC上运行程序并比较结果.
我们很快想出了这个代码来计算素数:
#include <stdio.h>
#include <time.h>
void main() {
clock_t start, end;
double runTime;
start = clock();
int i, num = 1, primes = 0;
while (num <= 1000) {
i = 2;
while (i <= num) {
if(num % i == 0)
break;
i++;
}
if (i == num)
primes++;
system("clear");
printf("%d prime numbers calculated\n",primes);
num++;
}
end = clock();
runTime = (end - start) / (double) CLOCKS_PER_SEC;
printf("This machine calculated all %d prime numbers under …Run Code Online (Sandbox Code Playgroud) 我对使用Sandy-Bridge和Haswell可以完成每个核心每个循环的触发器感到困惑.据我所知,对于SSE,每个核心每个周期应该为4个触发器,对于AVX/AVX2,每个核心每个周期应该有8个触发器.
这似乎在这里得到验证, 如何实现每个周期4个FLOP的理论最大值? ,这里, Sandy-Bridge CPU规范.
然而,下面的链接似乎表明,Sandy-bridge每个核心每个周期可以执行16个触发器,每个核心每个循环使用Haswell 32个触发器 http://www.extremetech.com/computing/136219-intels-haswell-is-an-前所未有-threat-to-nvidia-amd.
谁可以给我解释一下这个?
编辑:我现在明白为什么我感到困惑.我认为术语FLOP仅指单浮点(SP).我现在看到如何在每个循环中实现理论最大值4 FLOP的测试?实际上是双浮点(DP),因此它们为SSE实现4个DP FLOP /周期,为AVX实现8个DP FLOP /周期.在SP上重做这些测试会很有趣.
我正在阅读"加速C++".我发现一句话说"有时double执行速度比floatC++ 快".读完句子后,我感到困惑float和double工作.请向我解释这一点.
为什么,在硬件执行操作的最低级别和所涉及的一般底层操作(即:运行代码时所有编程语言的实际实现的一般性),矢量化通常比循环更快?
当使用矢量化时,计算机在循环时做了什么(我说的是计算机执行的实际计算,而不是程序员编写的计算),或者它有什么不同的做法?
我一直无法说服自己为什么差异应该如此重要.我可能会说服矢量化代码在某处削减一些循环开销,但计算机仍然必须执行相同数量的操作,不是吗?例如,如果我们将大小为N的向量乘以标量,我们将使用N次乘法执行任一方式,不是吗?
以下是C++中的一个简单循环.计时器使用QueryPerformanceCounter()并且非常准确.我发现Java需要60%的时间用C++,这不可能是什么?!我在这做错了什么?即使是严格的别名(这里没有包含在代码中)也没有任何帮助......
long long var = 0;
std::array<int, 1024> arr;
int* arrPtr = arr.data();
CHighPrecisionTimer timer;
for(int i = 0; i < 1024; i++) arrPtr[i] = i;
timer.Start();
for(int i = 0; i < 1024 * 1024 * 10; i++){
for(int x = 0; x < 1024; x++){
var += arrPtr[x];
}
}
timer.Stop();
printf("Unrestricted: %lld us, Value = %lld\n", (Int64)timer.GetElapsed().GetMicros(), var);
Run Code Online (Sandbox Code Playgroud)
这个C++在大约9.5秒内完成.我正在使用英特尔编译器12.1与主机处理器优化(特别是我的)和一切最大化.所以这是英特尔编译器的最佳选择!自动并行化有趣地消耗70%的CPU而不是25%但是不能更快地完成工作;)...
现在我使用以下Java代码进行比较:
long var = 0;
int[] arr = new int[1024];
for(int i = 0; i < 1024; i++) …Run Code Online (Sandbox Code Playgroud) 我的应用程序中有一个乘法添加内核,我想提高它的性能.
我使用英特尔酷睿i7-960(3.2 GHz时钟)并已使用SSE内在函数手动实现内核,如下所示:
for(int i=0; i<iterations; i+=4) {
y1 = _mm_set_ss(output[i]);
y2 = _mm_set_ss(output[i+1]);
y3 = _mm_set_ss(output[i+2]);
y4 = _mm_set_ss(output[i+3]);
for(k=0; k<ksize; k++){
for(l=0; l<ksize; l++){
w = _mm_set_ss(weight[i+k+l]);
x1 = _mm_set_ss(input[i+k+l]);
y1 = _mm_add_ss(y1,_mm_mul_ss(w,x1));
…
x4 = _mm_set_ss(input[i+k+l+3]);
y4 = _mm_add_ss(y4,_mm_mul_ss(w,x4));
}
}
_mm_store_ss(&output[i],y1);
_mm_store_ss(&output[i+1],y2);
_mm_store_ss(&output[i+2],y3);
_mm_store_ss(&output[i+3],y4);
}
Run Code Online (Sandbox Code Playgroud)
我知道我可以使用压缩的fp向量来提高性能,我已经成功完成了,但我想知道为什么单个标量代码无法满足处理器的峰值性能.
我的机器上的这个内核的性能是每个周期大约1.6个FP操作,而每个周期最大的是2个FP操作(因为FP add + FP mul可以并行执行).
如果我对研究生成的汇编代码是正确的,理想的时间表将如下所示,其中mov指令需要3个周期,从依赖指令的加载域到FP域的切换延迟需要2个周期,FP乘以4个循环,FP添加需要3个循环.(注意,乘法 - > add的依赖性不会导致任何切换延迟,因为操作属于同一个域).

根据测量的性能(最大理论性能的约80%),每8个周期有大约3个指令的开销.
我想要:
当然,存在缓存未命中和数据错位的问题,这可能会增加移动指令的延迟,但是还有其他因素可以在这里发挥作用吗?像寄存器读取档位或什么?
我希望我的问题很明确,在此先感谢您的回复!
更新:内循环的程序集如下所示:
...
Block 21:
movssl (%rsi,%rdi,4), %xmm4
movssl (%rcx,%rdi,4), %xmm0
movssl 0x4(%rcx,%rdi,4), %xmm1 …Run Code Online (Sandbox Code Playgroud) 很长一段时间以来,我一直认为C++比JavaScript更快.然而,今天我制作了一个基准脚本来比较两种语言中浮点计算的速度,结果令人惊叹!
JavaScript似乎比C++快4倍!
我让这两种语言在我的i5-430M笔记本电脑上做同样的工作,执行a = a + b了1亿次.C++大约需要410毫秒,而JavaScript大约需要120毫秒.
我真的不知道为什么JavaScript在这种情况下运行如此之快.有谁能解释一下?
我用于JavaScript的代码是(使用Node.js运行):
(function() {
var a = 3.1415926, b = 2.718;
var i, j, d1, d2;
for(j=0; j<10; j++) {
d1 = new Date();
for(i=0; i<100000000; i++) {
a = a + b;
}
d2 = new Date();
console.log("Time Cost:" + (d2.getTime() - d1.getTime()) + "ms");
}
console.log("a = " + a);
})();
Run Code Online (Sandbox Code Playgroud)
C++的代码(由g ++编译)是:
#include <stdio.h>
#include <ctime>
int main() {
double a = 3.1415926, b = 2.718;
int i, …Run Code Online (Sandbox Code Playgroud) 我一直看到人们声称MOV指令可以在x86中免费,因为寄存器重命名.
对于我的生活,我无法在一个测试用例中验证这一点.每个测试用例我尝试揭穿它.
例如,这是我用Visual C++编译的代码:
#include <limits.h>
#include <stdio.h>
#include <time.h>
int main(void)
{
unsigned int k, l, j;
clock_t tstart = clock();
for (k = 0, j = 0, l = 0; j < UINT_MAX; ++j)
{
++k;
k = j; // <-- comment out this line to remove the MOV instruction
l += j;
}
fprintf(stderr, "%d ms\n", (int)((clock() - tstart) * 1000 / CLOCKS_PER_SEC));
fflush(stderr);
return (int)(k + j + l);
}
Run Code Online (Sandbox Code Playgroud)
这为循环生成以下汇编代码(随意生成这个你想要的;你显然不需要Visual C++):
LOOP:
add edi,esi
mov …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) c++ ×5
performance ×5
c ×3
intel ×3
assembly ×2
avx ×2
benchmarking ×1
c++-faq ×1
cpu ×1
cray ×1
double ×1
flops ×1
fma ×1
gcc ×1
instructions ×1
java ×1
javascript ×1
linux ×1
low-level ×1
namespaces ×1
std ×1
windows ×1
x86 ×1