在MSVC(在Windows)和GCC(在Linux上)编译的代码中,Ivy Bridge系统的性能差异很大。 该代码做密集matrix乘法。 我得到GCC峰值的70%,MSVC只有50%。 我想我可能已经把它们的差异分离出来了,它们是如何将以下三个内在因素进行转换的。 __m256 breg0 = _mm256_loadu_ps(&b[8*i]) _mm256_add_ps(_mm256_mul_ps(arge0,breg0), tmp0) GCC做到这一点 vmovups ymm9, YMMWORD PTR [rax-256] vmulps ymm9, ymm0, ymm9 vaddps ymm8, ymm8, ymm9 MSVC做到这一点 vmulps ymm1, ymm2, YMMWORD PTR [rax-256] vaddps ymm3, ymm1, ymm3 请问有人可以解释一下,为什么这两个解决scheme可以在性能上有如此大的差异呢? 尽pipeMSVC使用一个较less的指令,它将负载连接到mult,也许这使得它更依赖(也许负载不能乱序)? 我的意思是常春藤桥可以在一个时钟周期内完成一个AVX负载,一个AVX mult和一个AVX添加,但这需要每个操作都是独立的。 也许问题在别处? 您可以在下面的最内层循环中看到GCC和MSVC的完整汇编代码。 您可以在这里看到循环的C ++代码循环展开,以达到Ivy Bridge和Haswell的最大吞吐量 g ++ -S -masm = intel matrix.cpp -O3 -mavx -fopenmp […]
xor eax, eax将始终将eax设置为零,对吧? 那么,为什么MSVC ++有时会把它放在我的可执行代码中呢? mov eax, 0更高效吗? 012B1002 in al,dx 012B1003 push ecx int i = 5; 012B1004 mov dword ptr [i],5 return 0; 012B100B xor eax,eax 另外, in al, dx做什么意思?
我有兴趣强制在Windows中刷新CPUcaching(出于基准testing的原因,我想仿效CPUcaching中没有数据开始),最好是基本的C实现或Win32调用。 有没有一种已知的方式来做这个系统调用,甚至像做一个大的memcpy一样鬼鬼祟祟? 英特尔i686平台(P4和以上也可以)。
为了说清楚,我不打算在这里进行任何移植,所以任何将我绑定到某个盒子的解决scheme都是可以的。 基本上,我有一个if语句,将99%的时间评估为真,并试图排除性能的每一个时钟,我可以发出某种编译器命令(使用GCC 4.1.2和x86 ISA,如果它很重要)告诉分支预测器,它应该caching该分支?
我一直在分析我们在Intel Core Duo上的一些核心math,并且在研究各种平方根的方法时,我注意到一些奇怪的事情:使用SSE标量运算,取相反的平方根并乘以它得到sqrt,比使用本地的sqrt操作码! 我用一个循环来testing它: inline float TestSqrtFunction( float in ); void TestFunc() { #define ARRAYSIZE 4096 #define NUMITERS 16386 float flIn[ ARRAYSIZE ]; // filled with random numbers ( 0 .. 2^22 ) float flOut [ ARRAYSIZE ]; // filled with 0 to force fetch into L1 cache cyclecounter.Start(); for ( int i = 0 […]
为了完成这个任务,我一直在想我的大脑一个星期,我希望这里有人能带领我走向正确的道路。 让我从讲师的指示开始: 你的任务与我们第一个实验任务相反,那就是优化素数程序。 你在这个任务中的目的是让程序变得悲观,也就是让它运行得更慢。 这两个都是CPU密集型的程序。 他们需要几秒钟在我们的实验室PC上运行。 你不能改变algorithm。 为了使程序最优化,请使用您对Intel i7pipe道运行方式的了解。 想象一下如何重新排列指令path来引入WAR,RAW和其他危险。 想想如何最大限度地减lesscaching的有效性。 是恶魔无能。 这项任务给了Whetstone或Monte-Carlo项目的select。 caching有效性评论大多只适用于Whetstone,但我select了Monte-Carlo模拟程序: // Un-modified baseline for pessimization, as given in the assignment #include <algorithm> // Needed for the "max" function #include <cmath> #include <iostream> // A simple implementation of the Box-Muller algorithm, used to generate // gaussian random numbers – necessary for the […]
目前正在使用x86处理器开发结构化计算机组织的类项目。 我访问的值是一个1字节的字符,但我不知道如何将其与大写字母进行比较。 他们说使用hex格式的ASCII表,但我不知道如何比较这两个。 void changeCase (char char_array[], int array_size ) { __asm{ // BEGIN YOUR CODE HERE mov eax, char_array; //eax is base image mov edi, 0; readArray: cmp edi, array_size; jge exit; mov ebx, edi; //using ebx as offset shl ebx, 2; mov cl, [eax + ebx]; //using ecx to be the storage register […]
我创build了一个使用SIMD 64位* 64位到128位的函数。 目前我已经使用SSE2(强大的SSE4.1)来实现它。 这意味着它同时执行两个64b * 64b到128b的产品。 同样的想法可以扩展到AVX2或AVX512同时提供四个或八个64b * 64到128b产品。 我基于我的algorithm在http://www.hackersdelight.org/hdcodetxt/muldws.c.txt 该algorithm执行一个无符号乘法,一个有符号乘法和两个有符号*无符号乘法。 使用_mm_mul_epi32和_mm_mul_epu32可以很容易地执行带符号的*无符号*无符号操作。 但混合签名和未签名的产品给我带来了麻烦。 考虑一下例子。 int32_t x = 0x80000000; uint32_t y = 0x7fffffff; int64_t z = (int64_t)x*y; 双字产品应该是0xc000000080000000 。 但是如果你认为你的编译器知道如何处理混合types,你怎么能得到这个呢? 这就是我想到的: int64_t sign = x<0; sign*=-1; //get the sign and make it all ones uint32_t t = abs(x); //if x<0 take two's complement again uint64_t […]
我已经阅读了各种优化指南,声称ADD 1比在x86中使用INC更快。 这是真的吗?
我想知道这些说明之间的区别是什么: MOV AX, [TABLE-ADDR] 和 LEA AX, [TABLE-ADDR]