C vs Goループと単純な数学

Cでのプログラミングにうんざりしていたとき、多くの人と同じように、Goに興味がありました。 厳密に型指定され、コンパイルされているため、非常に生産的です。 そしてここで、Goの作成者がループと数値を使用して作業を最適化するのにどれだけ混乱しているかを知りたいと思いました。



まず、Cの動作を確認します。



このような単純なコードを作成します。



#include <stdint.h> #include <stdio.h> int main() { uint64_t i; uint64_t j = 0; for ( i = 10000000; i>0; i--) { j ^= i; } printf("%lu\n", j); return 0; }
      
      





O2でコンパイルします:



 564: 31 d2 xor %edx,%edx 566: b8 80 96 98 00 mov $0x989680,%eax 56b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1) 570: 48 31 c2 xor %rax,%rdx 573: 48 83 e8 01 sub $0x1,%rax 577: 75 f7 jne 570 <main+0x10>
      
      





実行時間を取得します。



実数0m0,023s

ユーザー0m0,019s

sys 0m0,004s



加速する場所はないように思えますが、最新のプロセッサがあり、そのような操作には高速のsseレジスタがあります。 オプションgcc -mfpmath = sse -msse4.2を試しますが、結果は同じです。

-O3と歓声を追加:



  57a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) 580: 83 c0 01 add $0x1,%eax 583: 66 0f ef c8 pxor %xmm0,%xmm1 587: 66 0f d4 c2 paddq %xmm2,%xmm0 58b: 3d 40 4b 4c 00 cmp $0x4c4b40,%eax 590: 75 ee jne 580 <main+0x20>
      
      





SSE2コマンドとSSEレジスタが使用され、パフォーマンスが3倍向上することがわかります。



実数0m0,006s

ユーザー0m0,006s

sys 0m0,000s



外出先でも:



 package main import "fmt" func main() { i := 0 j := 0 for i = 10000000; i>0; i-- { j ^= i } fmt.Println(j) }
      
      





 0x000000000048211a <+42>: lea -0x1(%rax),%rdx 0x000000000048211e <+46>: xor %rax,%rcx 0x0000000000482121 <+49>: mov %rdx,%rax 0x0000000000482124 <+52>: test %rax,%rax 0x0000000000482127 <+55>: ja 0x48211a <main.main+42>
      
      







タイミングGo:

レギュラーゴー:

実数0m0,021s

ユーザー0m0,018s

sys 0m0,004s



gccgo:

実数0m0,058s

ユーザー0m0,036s

sys 0m0.014s



CおよびO2の場合のように、パフォーマンスもgccgoに同じ結果を設定しますが、通常のGo(1.10.4)コンパイラよりも長く機能します。 どうやら、通常のコンパイラーがスレッドの起動を完全に最適化するという事実(私の場合、5つの追加スレッドが4つのコアで作成された)により、アプリケーションはより高速に実行されます。



おわりに





私はまだ標準のGoコンパイラをループのsse命令で動作させることができました。ループをネイティブにsse floatにスリップさせることによって。



 package main // +build amd64 import "fmt" func main() { var i float64 = 0 var j float64 = 0 for i = 10000000; i>0; i-- { j += i } fmt.Println(j) }
      
      







0x0000000000484bbe <+46>: movsd 0x4252a(%rip),%xmm3 # 0x4c70f0 <$f64.3ff0000000000000>

0x0000000000484bc6 <+54>: movups %xmm0,%xmm4

0x0000000000484bc9 <+57>: subsd %xmm3,%xmm0

0x0000000000484bcd <+61>: addsd %xmm4,%xmm1

0x0000000000484bd1 <+65>: xorps %xmm2,%xmm2

0x0000000000484bd4 <+68>: ucomisd %xmm2,%xmm0

0x0000000000484bd8 <+72>: ja 0x484bbe <main.main+46>








All Articles